我有这样定义的合同:
[OperationContract]
[WebGet(UriTemplate = "/GetX?myStr={myStr}&myX={myX}", BodyStyle = WebMessageBodyStyle.Wrapped)]
string GetX(string myStr, int? myX);
我得到一个异常:[出现InvalidOperationException:操作'的getX'合同'IMyGet'有类型的名为'MYX'查询变量'System.Nullable 1[System.Int32]', but type 'System.Nullable
1 [System.Int32 ]”不是由兑换‘QueryStringConverter’。 为UriTemplate查询值的变量必须具有可以通过“QueryStringConverter”被转换的类型。]
找不到任何关于此错误的任何东西,除了下面的链接: http://blog.rolpdog.com/2007/07/webget-and-webinvoke-rock.html这是一个小老头,反正不是一个解决方案。
任何想法除了做什么摆脱可空参数?
谢谢。
是的,你可以有WCF空的参数的。 我觉得这里的问题是,QueryStringConverter不空的参数的工作。
该怎么办? 你需要使用UriTemplate属性? 如果您发布此为“典型的Web服务”,那么你就没有这个问题。
另一种选择是按照你提供的链接提醒 - 即收到MYX参数为字符串,然后将其转换为int ?,其中,(说)“n”是零。 不漂亮。
还有就是这个问题,不需要任何黑客的解决方案。 它看起来像一个大量的工作,但它不是真的,并使得很多的意义,如果你通读一遍。 问题的核心是,的确存在未解决的bug (如.NET 4中),这意味着WebServiceHost不使用自定义QueryStringConverters。 所以,你需要一些额外的工作,并了解WebHttpEndpoints WCF的配置是如何工作的。 以下列举了您的解决方案。
首先,自定义QueryStringConverter允许省略它们,或者提供一个空字符串查询字符串中要提供空值:
public class NullableQueryStringConverter : QueryStringConverter
{
public override bool CanConvert(Type type)
{
var underlyingType = Nullable.GetUnderlyingType(type);
return (underlyingType != null && base.CanConvert(underlyingType)) || base.CanConvert(type);
}
public override object ConvertStringToValue(string parameter, Type parameterType)
{
var underlyingType = Nullable.GetUnderlyingType(parameterType);
// Handle nullable types
if (underlyingType != null)
{
// Define a null value as being an empty or missing (null) string passed as the query parameter value
return String.IsNullOrEmpty(parameter) ? null : base.ConvertStringToValue(parameter, underlyingType);
}
return base.ConvertStringToValue(parameter, parameterType);
}
}
现在定制WebHttpBehavior,将设置自定义QueryStringConverter来代替标准的一个来使用。 需要注意的是,从WebHttpBehavior这种行为derivces让我们继承了一个REST端点所要求的行为,是非常重要的:
public class NullableWebHttpBehavior : WebHttpBehavior
{
protected override QueryStringConverter GetQueryStringConverter(OperationDescription operationDescription)
{
return new NullableQueryStringConverter();
}
}
现在,添加自定义行为的WebHttpEndpoint,使其使用自定义QueryStringConverter一个自定义的ServiceHost。 重要的是要注意在这段代码,是它的ServiceHost和NOT WebServiceHost派生。 否则上面提到的bug会阻止使用自定义QueryStringConverter这一点很重要:
public sealed class NullableWebServiceHost : ServiceHost
{
public NullableWebServiceHost()
{
}
public NullableWebServiceHost(object singletonInstance, params Uri[] baseAddresses) : base(singletonInstance, baseAddresses)
{
}
public NullableWebServiceHost(Type serviceType, params Uri[] baseAddresses) : base(serviceType, baseAddresses)
{
}
protected override void OnOpening()
{
if (this.Description != null)
{
foreach (var endpoint in this.Description.Endpoints)
{
if (endpoint.Binding != null)
{
var webHttpBinding = endpoint.Binding as WebHttpBinding;
if (webHttpBinding != null)
{
endpoint.Behaviors.Add(new NullableWebHttpBehavior());
}
}
}
}
base.OnOpening();
}
}
因为我们不是从WebServiceHost推导,我们需要做的工作,并确保我们的配置是正确的,以确保REST服务将正常工作。 像下面的内容是你所需要的。 在这种配置中,我也有一个WS HTTP端点设置,因为我需要(使用WS HTTP作为其更好)和移动设备(使用REST)来访问来自两个C#这项服务。 可以省略配置这个端点,如果你不需要它。 需要注意的重要一点是,你不需要自定义端点行为了。 这是因为我们现在将我们结合自定义QueryStringConverter自己的自定义端点行为。 它从WebHttpBehavior派生这是配置添加了什么,使得它现在是多余的。
<system.serviceModel>
<services>
<service behaviorConfiguration="ServiceBehavior" name="MyNamespace.Service1">
<endpoint binding="webHttpBinding" bindingConfiguration="WebHttpBinding" contract="MyNamespace.IService1" />
<endpoint address="ws" binding="wsHttpBinding" bindingConfiguration="WsHttpBinding" contract="MyNamespace.IService1" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<bindings>
<webHttpBinding>
<binding name="WebHttpBinding">
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
</webHttpBinding>
<wsHttpBinding>
<binding name="WsHttpBinding">
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" httpHelpPageEnabled="false" httpsHelpPageEnabled="true" />
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
做的最后一件事是创建一个自定义ServiceHostFactory并告诉SVC文件来使用它,这将导致使用的所有的自定义代码。 当然,你也可以创建一个能够允许您添加的配置行为的自定义元素,但我认为这种行为基于代码的方法比较好,因为它是不太可能你会想删除处理可空类型的能力,因为它会破坏你的服务:
public sealed class NullableWebServiceHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
return new NullableWebServiceHost(serviceType, baseAddresses);
}
}
更改您的Service.svc文件下面的标记:
<%@ ServiceHost Service="MyNamespace..Service1" CodeBehind="Service1.svc.cs" Factory="MyNamespace.NullableWebServiceHostFactory" %>
现在你可以在你的服务接口使用可空类型没有任何问题,只是省略该参数或将其设置为空字符串。 以下资源也许对你更多的帮助:
- 自定义QueryStringConverter
- 自QueryStringConverter绑定了自定义配置元素
希望这可以帮助!
其实...你绝对可以有空的参数的,或者是不被支持的任何其他类型的参数QueryStringConverter
开箱。 所有你需要做的是延长QueryStringConverter
支持任何类型的,你将需要。 见接受的答案在这个岗位==>
在WCF的Web编程模型,一个人如何可以编写查询字符串参数数组的经营合同(即具有相同的名称)?
呜呜,快速溶液(不漂亮)是接受可为空的参数作为在WCF各自接口和服务代码的字符串。