В модели веб-программирования WCF можно написать рабочий контракт с массивом параметров строки запроса (т.е. С тем же именем)?

Используя модель веб-программирования 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-сервис, который предоставляет ресурс с массивом параметров, не прибегая к бессвязному интерфейсу?

Ответы

Ответ 1

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

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

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

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

Ответ 2

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

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

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

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

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

Из MSDN:

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

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

Ответ 3

Помните, что в 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 = null

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

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

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