HTML 窗体处理程序示例

本示例演示如何扩展 Windows Communication Foundation (WCF) Web 编程模型以处理 HTML 窗体发布,如那些用 Web 浏览器生成的发布。

提示

此示例需要安装 .NET Framework 3.5 版才能生成和运行。若要打开项目和解决方案文件,需要使用 Visual Studio 2008。

分析窗体数据

HTML 窗体发布编码为 HTTP POST 实体正文内的一系列名称/值对,其内容类型为 application/x-www-form-urlencoded。当用原始实体正文字符串表示时,ParseQueryString 方法可以将这些值分析成一个 NameValueCollection。为了可以将此名称/值集合作为参数传递给 WCF 服务操作,示例中的 FormDataProcessor 类使用了 IDispatchMessageFormatter 扩展点。

FormDataProcessor 类的 DeserializeRequest 实现使用 ParseQueryString 来分析 NameValueCollection 中的实体正文。可以使用 Microsoft 语言集成查询 (LINQ) 来填充附加方法参数,这些参数的值可通过用于将请求调度到操作的 UriTemplateMatch 获得。

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;
    };
}

用自定义 RequestFormatter 扩展 WebHttpBehavior

可以从 WebHttpBehavior 派生一个类来扩展每个操作的 WCF 运行时。在本示例中,FormProcessingBehavior 重写 GetRequestDispatchFormatter 以便为最后一个参数是 NameValueCollection 的任何 Web 调用操作插入一个 FormDataFormatter

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);
        }
    }
}

实现窗体处理服务

FormProcessingBehavior 隐藏有关 HTML 窗体处理的详细信息。然后可以编写服务实现,而不需专门了解有关 HTML 窗体的详细信息,如下面的示例代码所示。

[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);
        }
        );
}

提示

有关 StreamMessageHelper 类的详细说明,请参见推送式流处理示例

承载窗体处理服务

服务是使用 ServiceHost 类进行承载的。自定义 FormProcessingBehavior 是在调用 Open 之前将手动添加到 ServiceEndpoint 中的,如下面的示例代码所示。

ServiceHost host = new ServiceHost(typeof(Service), new Uri("https://localhost:8000/FormTest"));

ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(Service), new WebHttpBinding(), "");
endpoint.Behaviors.Add(new FormProcessingBehavior());

另外,通过禁用 ServiceMetadataBehaviorServiceDebugBehavior,可以移除默认存在的 HTTP GET 终结点(生成默认 HTML 帮助页的终结点),如下面的示例代码所示。

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;
}

运行示例

若要查看示例的输出,请编译并运行 HtmlFormProcessing 项目,然后用 Web 浏览器导航到 https://localhost:8000/FormTest。

另请参见

任务

推送式流处理示例

Send comments about this topic to Microsoft.
© 2007 Microsoft Corporation. All rights reserved.