Как в модели веб-программирования 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);

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

the query string must have 'name=value' pairs with unique names. Note that the names are case-insensitive. See the documentation for UriTemplate for more details.

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

Если вам не нужен [WebGet], вы можете использовать [WebInvoke(Method = "POST"], в котором разрешены массивы / коллекции. См. этот ответ.

stomy 12.04.2018 20:59
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
13
1
16 448
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Я реализовал простой пользовательский QueryStringConverter, чтобы вы могли сделать qs1 строкой [], а затем разделить переменную строки запроса запятыми (например, http: // сервер / служба / 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, который обрабатывает параметры string []:

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 и ниже).

Есть идеи, как сделать так, чтобы он выглядел как сервер / служба /…? Мы могли бы, конечно, взломать его, чтобы он возвращал отформатированную строку с именем параметра вместо запятой.

Dilip Krishnan 10.12.2008 23:58

Отлично! Я столкнулся с проблемой, из-за которой мое расширение поведения не загружалось, если я полностью не уточнил имя типа с версией сборки, ключом и т. д. См. nayyeri.net/…

Sebastian Good 12.08.2010 02:03

В WCF 4 есть ошибка, из-за которой WebServiceHost не вызывает переопределенный метод GetQueryStringConverter. См. connect.microsoft.com/VisualStudio/feedback/details/616486/…

Daniel 14.11.2010 20:51

это действительно работает? Я не смог заставить это работать

Daniel 12.03.2011 22:47

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

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

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

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

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

Из MSDN:

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

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

Имейте в виду, что в 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

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

Configuration Error
Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.

Parser Error Message: Invalid element in configuration. The extension name 'CustomWebHttp' is not registered in the collection at system.serviceModel/extensions/behaviorExtensions.

Другие вопросы по теме