使用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接口?
答案 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上记录的错误与此代码直接相关。在您尝试查询转换不同类型的几乎所有情况下,代码实际上都不起作用。
在浪费时间创建无法正常工作的自定义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的集合中注册。