В модели веб-программирования WCF, как можно написать контракт операции с массивом параметров строки запроса (то есть с тем же именем)? - PullRequest
13 голосов
/ 10 декабря 2008

Используя модель веб-программирования WCF, можно указать контракт на работу следующим образом:

[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);

Мы получаем сообщение об ошибке во время выполнения при вызове метода:

строка запроса должна содержать пары «имя = значение» с уникальными именами. Обратите внимание, что имена не чувствительны к регистру. См. Документацию для UriTemplate для получения более подробной информации.

Как определить службу HTTP, которая предоставляет ресурс с массивом параметров, не прибегая к интерфейсу loosey-goosey?

Ответы [ 3 ]

27 голосов
/ 10 декабря 2008

Я реализовал простой пользовательский 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, который обрабатывает параметры строки []:

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 для обработки других типов, которые по умолчанию не доступны, таких как типы значений, допускающие значение NULL.

ПРИМЕЧАНИЕ. В microsoft connect зарегистрирована ошибка, которая напрямую связана с этим кодом. Код фактически не работает практически во всех случаях, когда вы пытаетесь преобразовать запрос различных типов.

http://connect.microsoft.com/VisualStudio/feedback/details/616486/bug-with-getquerystringconverter-not-being-called-by-webservicehost#tabs

Пожалуйста, убедитесь, что вы внимательно прочитали это, прежде чем тратить часы своего времени на создание пользовательских конвертеров строк запросов REST, которые не могут работать. (Относится к Framework 4.0 и ниже).

5 голосов
/ 11 декабря 2008

Чтобы ответить на ваш комментарий к моему другому ответу:

Вы можете использовать параметр подстановки в конце строки запроса, например

[WebGet(ResponseFormat = WebMessageFormat.Xml,
        UriTemplate = "SomeRequest?qs1={*qs1}")]
XElement SomeRequest2(string qs1);

Таким образом, строковым параметром qs1 будет вся необработанная строка запроса после qs1 =, вы можете затем проанализировать это вручную в своем коде.

QueryStringConverter полагается на форматирование строки запроса, поэтому выполнение чего-либо в точности так, как вы хотите, невозможно без возможности переписать QueryStringConverter вместо небольших переопределений, которые мы сделали в другом ответе.

Из MSDN:

Сегменты подстановочного знака должны соответствовать следующим правилам:

  • Для каждой строки шаблона может быть не более одного именованного сегмента с подстановочными знаками.
  • Именованный подстановочный сегмент должен появляться в крайнем правом сегменте пути.
  • Именованный подстановочный сегмент не может сосуществовать с анонимным подстановочным сегментом в пределах одной строки шаблона.
  • Имя именованного сегмента с подстановочными знаками должно быть уникальным.
  • Именованные сегменты подстановочных знаков не могут иметь значения по умолчанию.
  • Именованные сегменты с подстановочными символами не могут заканчиваться на «/рабат.
2 голосов
/ 24 декабря 2009

Помните, что в WCF 3.5 вы должны указать полное имя сборки в:

   <extensions>
    <behaviorExtensions>
      <add name="customWebHttp" type="NameSpace.CustomHttpBehaviorExtensionElement, MyAssemblyName, NOT SUFFICIENT HERE" />
    </behaviorExtensions>
  </extensions>

Просто так: SampleService.CustomBehavior, SampleService, Версия = 1.0.0.0, Культура = нейтральная, PublicKeyToken = ноль

В противном случае вы получите исключение:

Ошибка конфигурации
Описание: во время обработки файла конфигурации, необходимого для обслуживания этого запроса, произошла ошибка. Пожалуйста, просмотрите подробности конкретной ошибки ниже и измените файл конфигурации соответствующим образом.

Сообщение об ошибке парсера: недопустимый элемент в конфигурации. Имя расширения 'CustomWebHttp' не зарегистрировано в коллекции по адресу system.serviceModel / extensions / поведениеExtensions.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...