Я пытаюсь разрешить гибкие параметры метода внутри моей службы WCF, но я столкнулся с несколькими проблемами.
Сначала я просто объясню цель.Я хочу иметь возможность объявлять веб-метод, такой как:
[OperationContract, WebGet(ResponseFormat = WebMessageFormat.Json, RequestFormat=WebMessageFormat.Json)]
public StatisticEventArgs GetStatistic(DateTime? startDate = null, DateTime? endDate = null)
{
return new StatisticEventArgs() { Count = 50; }
}
и иметь возможность вызывать его через метод jquery $ .ajax:
$.ajax({
type: 'GET',
url: 'service/MyService.svc,
data: '', // or '?startDate=12/1/2011&endDate=12/10/2011','?startDate=12/1/2011', etc. Any combination of startDate or endDate parameters
contentType: "application/json",
dataType: "json",
processdata: true,
success: endCallback,
error: errorCallback
});
Цель состоит в том, чтобысоздайте методы, где все параметры являются необязательными, и для тех параметров, которые не указаны, вместо них будет использоваться их значение по умолчанию.В этом примере я хочу иметь возможность вызывать метод, в котором я могу предоставить либо параметр startDate, либо endDate, либо оба, либо ни один из них.
Я быстро обнаружил, что класс QueryStringParameter по умолчанию (как видно из этого вопроса: В модели веб-программирования WCF как можно написать контракт операции с массивом параметров строки запроса (т. е. с тем же именем)? ) не поддерживает типы, допускающие обнуление, но JsonQueryStringConverter делает.Кроме того, как отмечено в приведенном выше вопросе, в .NET 4.0 и ниже имеется ошибка, связанная с этим решением, которая препятствует созданию экземпляра класса JsonQueryStringConverter в пользовательском поведении (GetQueryStringConverter никогда не вызывается).
После дополнительных исследований я обнаружил эту ошибку Microsoft , которая обеспечивает обходной путь, но только при создании экземпляра службы с помощью кода.
Мой вопрос: как я могу применить этот обходной путь в веб-службе ASP.NET WCF? Мне кажется, мне нужно настроить его в web.config, но я неуверен, как это сделать.Вот соответствующий пример кода для того, что у меня есть (я изменил имена, поэтому он может содержать некоторые опечатки):
Класс WCF, содержащийся в моем проекте веб-приложения ASP.NET:
namespace Namespace.Services
{
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class MyService
{
[OperationContract, WebGet(ResponseFormat = WebMessageFormat.Json, RequestFormat=WebMessageFormat.Json)]
public StatisticEventArgs GetStatistic(DateTime? startDate = null, DateTime? endDate = null)
{
return new StatisticEventArgs() { Count = 50; }
}
public class NullableTypeBehaviorBehaviorExtension : BehaviorExtensionElement
{
public override Type BehaviorType
{
get { return typeof(NullableTypeBehavior); }
}
protected override object CreateBehavior()
{
return new NullableTypeBehavior();
}
}
public class NullableTypeBehavior : WebHttpBehavior
{
protected override System.ServiceModel.Dispatcher.QueryStringConverter GetQueryStringConverter(OperationDescription operationDescription)
{
return new JsonQueryStringConverter();
}
}
}
Javascript:
$.ajax({
type: 'GET',
url: 'service/MyService.svc/GetStatistic',
data: '', // or '?startDate=12/1/2011&endDate=12/10/2011','?startDate=12/1/2011', etc. Any combination of startDate or endDate parameters
contentType: "application/json",
dataType: "json",
processdata: true,
success: endCallback,
error: errorCallback
});
web.config:
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="nullableTypeBehavior" type="Namespace.Services.NullableTypeBehaviorBehaviorExtension, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</behaviorExtensions>
</extensions>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"></serviceHostingEnvironment>
<services>
<service name="MyWcfService">
<endpoint address="" behaviorConfiguration="MyBehaviorConfig"
binding="webHttpBinding" contract="Namespace.Services.MyService" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="web">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="MyBehaviorConfig">
<nullableTypeBehavior />
</behavior>
</endpointBehaviors>
</behaviors>
</client>
ОБНОВЛЕНИЕ 1: РЕШЕНИЕ
Вот ответ, который я закончил (любезно предоставлено VinayC):
public class CustomFactory : System.ServiceModel.Activation.ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type t, Uri[] baseAddresses)
{
return new CustomHost(t, baseAddresses);
}
}
public class CustomHost : ServiceHost
{
public CustomHost(Type t, params Uri[] baseAddresses) : base(t, baseAddresses) { }
protected override void OnOpening()
{
var nullableTypeBehavior = new NullableTypeBehavior();
foreach(var ep in this.Description.Endpoints)
{
ep.Behaviors.Add(nullableTypeBehavior);
}
base.OnOpening();
}
}
и в верхней части моего файла MyService.svc:
<%@ ServiceHost Language="C#" Debug="true" Service="Namespace.Services.MyService" CodeBehind="MyService.svc.cs" Factory="Namespace.Services.CustomFactory" %>
ОБНОВЛЕНИЕ 2: проблема с датами прохода для этого решения
В настоящее время проходные даты не работают:
http://localhost/Services/MyService.svc?startDate=11/10/2011&endDate=11/11/2011
, но эти запросы работают:
http://localhost/Services/MyService.svc?startDate=null&endDate=null
http://localhost/Services/MyService.svc
Похоже, это специфично для JsonQueryStringConverter, поэтому я собираюсь изучить его и опубликовать, когда найду решение.Похоже, что это должно быть достаточно просто для отладки.
ОБНОВЛЕНИЕ 3: Решение для проходящих дат:
Проблема в том, что даты, которые я проходил, не соответствуют ожидаемымформат для .NET JSON.Я передавал что-то вроде:
"12/01/2011"
и .NET JSON (включая JsonQueryStringConverter) ожидает этот формат:
"\/Date(1283219926108)\/"
Этот формат даты не является родным для javascript.Для того, чтобы получить дату в этом формате, я нашел этот пост.После добавления этого скрипта я могу сделать это в jQuery, и дата будет проанализирована соответствующим образом:
$.ajax({
type: 'GET',
url: 'service/MyService.svc/GetStatistic',
data: '?startDate=' + JSON.stringifyWCF(new Date('12/1/2011'))
contentType: "application/json",
dataType: "json",
processdata: true,
success: endCallback,
error: errorCallback
});
Кажется, все работает, как ожидалось.Я могу игнорировать любые необязательные параметры, установить для них значение null или задать для них значение, и все запросы будут работать.
Обновлена ошибка Microsoft с обходным решением.Обходной путь немного более элегантен, чем решение, представленное здесь.