Как добавить собственный заголовок HTTP к каждому вызову WCF? - PullRequest
149 голосов
/ 08 июня 2009

У меня есть служба WCF, которая размещена в службе Windows. Клиенты, которые используют эту службу, должны передавать идентификатор каждый раз, когда они вызывают методы службы (потому что этот идентификатор важен для того, что должен делать вызываемый метод). Я подумал, что было бы неплохо как-то поместить этот идентификатор в информацию заголовка WCF.

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

UPDATE: Клиентами, которые используют службу WCF, являются как приложения Windows, так и приложения Windows Mobile (с использованием Compact Framework).

Ответы [ 12 ]

170 голосов
/ 11 сентября 2009

Преимущество в том, что оно применяется к каждому вызову.

Создайте класс, который реализует IClientMessageInspector . В методе BeforeSendRequest добавьте свой пользовательский заголовок к исходящему сообщению. Это может выглядеть примерно так:

    public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request,  System.ServiceModel.IClientChannel channel)
{
    HttpRequestMessageProperty httpRequestMessage;
    object httpRequestMessageObject;
    if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name, out httpRequestMessageObject))
    {
        httpRequestMessage = httpRequestMessageObject as HttpRequestMessageProperty;
        if (string.IsNullOrEmpty(httpRequestMessage.Headers[USER_AGENT_HTTP_HEADER]))
        {
            httpRequestMessage.Headers[USER_AGENT_HTTP_HEADER] = this.m_userAgent;
        }
    }
    else
    {
        httpRequestMessage = new HttpRequestMessageProperty();
        httpRequestMessage.Headers.Add(USER_AGENT_HTTP_HEADER, this.m_userAgent);
        request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);
    }
    return null;
}

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

Вот отличный пример того, как добавить HTTP-заголовок user-agent ко всем сообщениям запроса. Я использую это в некоторых из моих клиентов. Вы также можете сделать то же самое на стороне службы, реализовав IDispatchMessageInspector .

Это то, что вы имели в виду?

Обновление: Я нашел этот список функций WCF, которые поддерживаются компактной средой. Я считаю, что инспекторы сообщений классифицируются как «Расширяемость каналов», которые, согласно этому сообщению, поддерживаются компактной структурой.

78 голосов
/ 08 июня 2009

Вы добавляете его к вызову, используя:

using (OperationContextScope scope = new OperationContextScope((IContextChannel)channel))
{
    MessageHeader<string> header = new MessageHeader<string>("secret message");
    var untyped = header.GetUntypedHeader("Identity", "http://www.my-website.com");
    OperationContext.Current.OutgoingMessageHeaders.Add(untyped);

    // now make the WCF call within this using block
}

А затем, на стороне сервера, вы берете его, используя:

MessageHeaders headers = OperationContext.Current.IncomingMessageHeaders;
string identity = headers.GetHeader<string>("Identity", "http://www.my-website.com");
33 голосов
/ 06 ноября 2009

Если вы просто хотите добавить один и тот же заголовок ко всем запросам к сервису, вы можете сделать это без любой кодировки! Просто добавьте узел заголовков с необходимыми заголовками под узлом конечной точки в файле конфигурации клиента

<client>  
  <endpoint address="http://localhost/..." >  
    <headers>  
      <HeaderName>Value</HeaderName>  
    </headers>   
 </endpoint>  
12 голосов
/ 25 января 2012

Вот еще одно полезное решение для ручного добавления пользовательских заголовков HTTP в ваш клиентский запрос WCF с использованием ChannelFactory в качестве прокси. Это должно быть сделано для каждого запроса, но достаточно просто для демонстрации, если вам просто нужно выполнить юнит-тестирование вашего прокси при подготовке к платформам, отличным от .NET.

// create channel factory / proxy ...
using (OperationContextScope scope = new OperationContextScope(proxy))
{
    OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = new HttpRequestMessageProperty()
    {
        Headers = 
        { 
            { "MyCustomHeader", Environment.UserName },
            { HttpRequestHeader.UserAgent, "My Custom Agent"}
        }
    };    
    // perform proxy operations... 
}
8 голосов
/ 31 марта 2014

Это похоже на ответ NimsDotNet, но показывает, как это сделать программно.

Просто добавьте заголовок к привязке

var cl = new MyServiceClient();

var eab = new EndpointAddressBuilder(cl.Endpoint.Address);

eab.Headers.Add( AddressHeader.CreateAddressHeader("ClientIdentification",  // Header Name
                                                    string.Empty,           // Namespace
                                                    "JabberwockyClient"));  // Header Value

cl.Endpoint.Address = eab.ToEndpointAddress();
5 голосов
/ 17 марта 2011
var endpoint = new EndpointAddress(new Uri(RemoteAddress),
                                               new[]
                                                   {
                                                       AddressHeader.CreateAddressHeader("APIKey", "",
                                                                                         "bda11d91-7ade-4da1-855d-24adfe39d174")
                                                   });
3 голосов
/ 25 октября 2016

Это работает для меня

TestService.ReconstitutionClient _serv = new TestService.TestClient (); * +1004 *

 using (OperationContextScope contextScope = new OperationContextScope(_serv.InnerChannel))
                {
                    HttpRequestMessageProperty requestMessage = new HttpRequestMessageProperty();

                    requestMessage.Headers["apiKey"] = ConfigurationManager.AppSettings["apikey"]; 
                    OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestMessage;
                    _serv.Method(Testarg);
                }
3 голосов
/ 08 июня 2009

Вы можете указать пользовательские заголовки в MessageContract .

Вы также можете использовать заголовки , которые хранятся в файле конфигурации и будут скопированы в заголовок всех сообщений, отправленных клиентом / службой. Это полезно для легкого добавления статического заголовка.

2 голосов
/ 08 июня 2009

Если я правильно понимаю ваше требование, простой ответ: вы не можете.

Это потому, что клиент службы WCF может быть создан любой третьей стороной, которая использует вашу службу.

ЕСЛИ у вас есть контроль над клиентами вашего сервиса, вы можете создать базовый класс клиента, который добавляет желаемый заголовок и наследует поведение рабочих классов.

2 голосов
/ 08 июня 2009

Контекст привязок в .NET 3.5 может быть именно тем, что вы ищете. Есть три из коробки: BasicHttpContextBinding, NetTcpContextBinding и WSHttpContextBinding. Протокол контекста в основном передает пары ключ-значение в заголовок сообщения. Ознакомьтесь со статьей Управление состоянием с помощью Durable Services в журнале MSDN.

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