Есть решение этой проблемы, не требующее никаких взломов. Это может показаться большим трудом, но на самом деле это не так и имеет большой смысл, если вы его прочитаете. Суть проблемы в том, что действительно существует неразрешенная ошибка (начиная с .NET 4), которая означает, что WebServiceHost не использует настраиваемые QueryStringConverters. Итак, вам нужно немного поработать и понять, как работает конфигурация WCF для WebHttpEndpoints. Ниже представлено решение для вас.
Во-первых, настраиваемый 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, что важно для наследования поведения, необходимого для конечной точки REST:
public class NullableWebHttpBehavior : WebHttpBehavior
{
protected override QueryStringConverter GetQueryStringConverter(OperationDescription operationDescription)
{
return new NullableQueryStringConverter();
}
}
Теперь настраиваемый ServiceHost, который добавляет настраиваемое поведение к WebHttpEndpoint, чтобы он использовал настраиваемый QueryStringConverter. В этом коде важно отметить, что он происходит от ServiceHost, а НЕ от WebServiceHost. Это важно, потому что в противном случае упомянутая выше ошибка помешает использованию настраиваемого 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-файлу использовать его, что приведет к использованию всего настраиваемого кода. Конечно, вы также можете создать настраиваемый элемент, который позволил бы вам добавить поведение в конфигурацию, но я думаю, что для этого поведения лучше использовать подход на основе кода, поскольку маловероятно, что вы захотите удалить возможность обработки типов, допускающих значение NULL, так как это нарушит вашу службу:
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" %>
Теперь вы можете без проблем использовать типы, допускающие значение NULL, в интерфейсе службы, просто опуская параметр или задав для него пустую строку. Следующие ресурсы могут быть вам более полезны:
Надеюсь это поможет!
person
Xcalibur
schedule
19.01.2012