在WCF Web编程模型中,如何使用查询字符串参数数组(即具有相同名称)编写操作协定?

时间:2008-12-10 00:24:24

标签: wcf web-services rest contract operation-contract

使用WCF Web编程模型可以指定操作合同,如下所示:

[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Xml, UriTemplate = "SomeRequest?qs1={qs1}&qs2={qs2}")]
XElement SomeRequest1(string qs1, string qs2);

现在,如果我们必须签订一份合同,接受一系列具有相同名称的参数(在本例中为 qs1 ),那么......

[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Xml, UriTemplate = "SomeRequest?qs1={qs1}&qs1={qs2}")]
 XElement SomeRequest2(string qs1, string qs2);

当我们调用方法时,我们在运行时收到错误消息:

  

查询字符串必须具有唯一名称的“name = value”对。请注意,名称不区分大小写。有关更多详细信息,请参阅UriTemplate的文档。

如何定义一个HTTP服务,该服务使用参数数组公开资源而不诉诸松散的goosey接口?

3 个答案:

答案 0 :(得分:27)

我已经实现了一个简单的自定义QueryStringConverter,这样你就可以使qs1成为一个字符串[]然后让查询字符串变量以逗号分隔(例如http://server/service/SomeRequest?qs1=val1,val2,val3,val4

[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Xml,
        UriTemplate = "SomeRequest?qs1={qs1}")]
XElement SomeRequest2(string[] qs1);

首先,您需要一个继承自WebHttpBehavior的类,以便我们可以注入自定义QueryStringConverter:

public class CustomHttpBehavior : System.ServiceModel.Description.WebHttpBehavior
{
    protected override System.ServiceModel.Dispatcher.QueryStringConverter GetQueryStringConverter(System.ServiceModel.Description.OperationDescription operationDescription)
    {
        return new CustomQueryStringConverter();
    }
}

然后我们的CustomQueryStringConverter处理string []参数:

public class CustomQueryStringConverter : System.ServiceModel.Dispatcher.QueryStringConverter
{
    public override bool CanConvert(Type type)
    {
        if (type == typeof(string[]))
        {
            return true;
        }

        return base.CanConvert(type);
    }

    public override object ConvertStringToValue(string parameter, Type parameterType)
    {
        if (parameterType == typeof(string[]))
        {
            string[] parms = parameter.Split(',');
            return parms;
        }

        return base.ConvertStringToValue(parameter, parameterType);
    }

    public override string ConvertValueToString(object parameter, Type parameterType)
    {
        if (parameterType == typeof(string[]))
        {
            string valstring = string.Join(",", parameter as string[]);
            return valstring;
        }

        return base.ConvertValueToString(parameter, parameterType);
    }
}

您需要做的最后一件事是创建一个行为配置扩展,以便运行时可以获取CustomWebHttpBehavior的实例:

public class CustomHttpBehaviorExtensionElement : System.ServiceModel.Configuration.BehaviorExtensionElement
{
    protected override object CreateBehavior()
    {
        return new CustomHttpBehavior();
    }

    public override Type BehaviorType
    {
        get { return typeof(CustomHttpBehavior); }
    }
}

现在我们将元素添加到配置扩展中,以便使用我们的CustomWebHttpBehavior,我们在行为中使用该扩展名而不是<webHttp />

 <system.serviceModel>
   <services>
     <service name="NameSpace.ServiceClass">
       <endpoint address="" behaviorConfiguration="MyServiceBehavior"
        binding="webHttpBinding" contract="NameSpace.ServiceClass" />
     </service>
   </services>
  <behaviors>
   <endpointBehaviors>
    <behavior name="MyServiceBehavior">
      <customWebHttp/>
    </behavior>
   </endpointBehaviors>
  </behaviors>
  <extensions>
    <behaviorExtensions>
      <add name="customWebHttp" type="NameSpace.CustomHttpBehaviorExtensionElement, MyAssemblyName" />
    </behaviorExtensions>
  </extensions>
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
 </system.serviceModel>

现在,您还可以扩展CustomQueryStringConverter以处理默认值不存在的其他类型,例如可为空的值类型。

注意:microsoft connect上记录的错误与此代码直接相关。在您尝试查询转换不同类型的几乎所有情况下,代码实际上都不起作用。

http://connect.microsoft.com/VisualStudio/feedback/details/616486/bug-with-getquerystringconverter-not-being-called-by-webservicehost#tabs

在浪费时间创建无法正常工作的自定义REST查询字符串转换器之前,请务必仔细阅读本文。 (适用于Framework 4.0及以下版本)。

答案 1 :(得分:5)

回复您对我的其他答案的评论:

您可以在查询字符串的末尾执行通配符参数,如

[WebGet(ResponseFormat = WebMessageFormat.Xml,
        UriTemplate = "SomeRequest?qs1={*qs1}")]
XElement SomeRequest2(string qs1);

这样qs1字符串参数将是qs1 =之后的整个原始查询字符串,然后您可以在代码中手动解析它。

QueryStringConverter依赖于查询字符串的格式,因此如果不重写QueryStringConverter而不是我们在另一个答案中做的一点覆盖,就不可能按照你想要的方式做一些事情。

来自MSDN:

通配符段必须遵循以下规则:

  • 每个模板字符串最多只能有一个命名通配符段。
  • 命名通配符段必须出现在路径中最右侧的段中。
  • 命名通配符段不能与同一模板字符串中的匿名通配符段共存。
  • 指定通配符段的名称必须是唯一的。
  • 命名通配符段不能包含默认值。
  • 命名通配符段不能以“/".
  • 结尾

答案 2 :(得分:2)

请注意,在WCF 3.5中,您必须在:

中指定完整的限定程序集名称
   <extensions>
    <behaviorExtensions>
      <add name="customWebHttp" type="NameSpace.CustomHttpBehaviorExtensionElement, MyAssemblyName, NOT SUFFICIENT HERE" />
    </behaviorExtensions>
  </extensions>

就像这样:SampleService.CustomBehavior,SampleService, Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null

否则你会得到例外:

  

配置错误
  描述:处理为此请求提供服务所需的配置文件时发生错误。请查看下面的具体错误详细信息并相应地修改配置文件。    

  分析器错误消息:配置中的元素无效。扩展名'CustomWebHttp'未在system.serviceModel / extensions / behaviorExtensions的集合中注册。

豫ICP备18024241号-1