接受的答案是有这个问题,不需要任何黑客的解决方案。它可能看起来像很多工作,但它不是真的,并且如果你仔细阅读它就会很有意义。问题的核心是确实有一个unresolved 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端点所要求的行为,这是很重要的:即增加了自定义行为的WebHttpEndpoint
public class NullableWebHttpBehavior : WebHttpBehavior
{
protected override QueryStringConverter GetQueryStringConverter(OperationDescription operationDescription)
{
return new NullableQueryStringConverter();
}
}
现在定制ServiceHost的,使其将使用自定义QueryStringConverter。此代码中要注意的重要一点是,它来自ServiceHost而不是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端点设置,因为我需要从C#(使用WS HTTP作为它的更好)和移动设备(使用REST)访问此服务。如果不需要,可以省略此端点的配置。需要注意的一点是,您不再需要自定义端点行为。这是因为我们现在添加了我们自己的自定义端点行为,该行为绑定了自定义的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派生类在框架4中不可用。请确保在尝试此操作之前查看错误。在发现它在实践中不起作用之前,我浪费了很多时间。 – Jim 2011-05-27 10:55:41