HTML Form Handler Sample

来源:互联网 发布:安卓应用市场网站源码 编辑:程序博客网 时间:2024/04/30 22:21

引自:MSDN http://msdn.microsoft.com/en-us/library/bb943485.aspx

 

Download sample

 

 

This sample shows how to extend the Windows Communication Foundation (WCF) Web Programming Model to handle HTML form posts, such as those produced by a Web browser.

Note: This sample requires that .NET Framework version 3.5 is installed to build and run. Visual Studio 2008 is required to open the project and solution files.

 

 

Parsing Form Data

HTML form posts are encoded as a series of name-value pairs inside of an HTTP POST entity body with a content type of application/x-www-form-urlencoded. The ParseQueryString method is capable of parsing these values into a NameValueCollection when presented with a raw entity body string. To allow this name/value collection to be passed as a parameter to a WCF service operation, the FormDataProcessor class in the sample uses the IDispatchMessageFormatter extensibility point.

The FormDataProcessor class’s implementation of DeserializeRequest uses ParseQueryString to parse the entity body in a NameValueCollection. A Microsoft Language Integrated Query (LINQ) is used to populate additional method parameters whose values are available through the UriTemplateMatch used to dispatch the request to the operation.

Copy Code
public void DeserializeRequest(System.ServiceModel.Channels.Message message, object[] parameters){    if (WebOperationContext.Current.IncomingRequest.ContentType                          != "application/x-www-form-urlencoded")        throw new InvalidDataException("Unexpected content type");    Stream s = StreamMessageHelper.GetStream(message);    string formData = new StreamReader(s).ReadToEnd();    NameValueCollection parsedForm =             System.Web.HttpUtility.ParseQueryString(formData);    UriTemplateMatch match =      message.Properties["UriTemplateMatchResults"] as UriTemplateMatch;    ParameterInfo[] paramInfos = operation.SyncMethod.GetParameters();    var binder = CreateParameterBinder( match );    object[] values = (from p in paramInfos                       select binder(p)).ToArray<Object>();    values[paramInfos.Length - 1] = parsedForm;    values.CopyTo(parameters, 0);}private Func<ParameterInfo, object> CreateParameterBinder(UriTemplateMatch match){    QueryStringConverter converter = new QueryStringConverter();    return delegate( ParameterInfo pi )    {        string value = match.BoundVariables[pi.Name];        if (converter.CanConvert(pi.ParameterType) && value != null)            return converter.ConvertStringToValue(value,                                                    pi.ParameterType);        else        return value;    };}

Extending WebHttpBehavior with a custom RequestFormatter

You can derive a class from the WebHttpBehavior to extend the WCF runtime for each operation. In the sample, FormProcessingBehavior overrides GetRequestDispatchFormatter to plug in a FormDataFormatter for any Web invoke operation whose last parameter is a NameValueCollection.

Copy Code
public class FormProcessingBehavior : WebHttpBehavior{    protected override IDispatchMessageFormatter GetRequestDispatchFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint)    {        //Messages[0] is the request message        MessagePartDescriptionCollection parts =                  operationDescription.Messages[0].Body.Parts;        //This formatter looks for [WebInvoke] operations that have        // their last parameter typed as NameValueCollection        if (operationDescription.Behaviors.Find<WebInvokeAttribute>()                 != null &&            parts.Count > 0 &&            parts[parts.Count - 1].Type == typeof(NameValueCollection))        {            return new FormDataRequestFormatter(operationDescription);        }        else        {            return base.GetRequestDispatchFormatter(                      operationDescription, endpoint);        }    }}

Implementing a Form Processing Service

The FormProcessingBehavior hides the details of HTML form processing. The service implementation can then be written without special knowledge of HTML forms, as shown in the following sample code.

Copy Code
[OperationContract][WebInvoke(UriTemplate = "ProcessForm/{templateParam1}/{templateParam2}")]public Message ProcessForm(string templateParam1, string templateParam2, NameValueCollection formData){    DumpValues(Console.Out, templateParam1, templateParam2, formData);    return StreamMessageHelper.CreateMessage(        MessageVersion.None, "",        "text/plain",        delegate(Stream output)        {          TextWriter writer = new StreamWriter(output);          DumpValues(writer, templateParam1, templateParam2, formData);        }        );}
Note: For a detailed description of the StreamMessageHelper class, see the Push-Style Streaming Sample.

 

 

Hosting the Form Processing Service

The service is hosted using the ServiceHost class. The custom FormProcessingBehavior is added to the ServiceEndpoint manually before calling Open as shown in the following sample code.

Copy Code
ServiceHost host = new ServiceHost(typeof(Service), new Uri("http://localhost:8000/FormTest"));ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(Service), new WebHttpBinding(), "");endpoint.Behaviors.Add(new FormProcessingBehavior());

Additionally, the HTTP GET endpoint that exists by default (the endpoint that produces the default HTML help page) is removed by disabling the ServiceMetadataBehavior and ServiceDebugBehavior as shown in the following sample code.

Copy Code
ServiceMetadataBehavior smb = host.Description.Behaviors.Find<ServiceMetadataBehavior>();if (smb != null)      {    smb.HttpGetEnabled = false;    smb.HttpsGetEnabled = false;}ServiceDebugBehavior sdb = host.Description.Behaviors.Find<ServiceDebugBehavior>();if (sdb != null){    sdb.HttpHelpPageEnabled = false;}

Running the sample

To view the output of the sample, compile and run the HtmlFormProcessing project and then navigate to http://localhost:8000/FormTest with a Web browser.

See Also

Other Resources

Push-Style Streaming Sample
原创粉丝点击