Как добавить пользовательский заголовок HTTP к каждому вызову WCF?
У меня есть служба WCF, которая размещена в службе Windows. Клиенты, использующие эту службу, должны передавать идентификатор каждый раз, когда они вызывают методы службы (поскольку этот идентификатор важен для того, что должен делать вызываемый метод). Я подумал, что это хорошая идея, чтобы как-то поместить этот идентификатор в информацию заголовка WCF.
Если это хорошая идея, как я могу добавить идентификатор автоматически в данные заголовка. Другими словами, всякий раз, когда пользователь вызывает WCF метод, идентификатор должен быть автоматически добавлен в заголовок.
обновление: Клиентами, использующими службу WCF, являются как приложения Windows, так и приложения Windows Mobile (с использованием Compact Framework).
12 ответов:
преимущество в том, что он применяется к каждому вызову.
создать класс, который реализует 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, которые поддерживаются compact framework. Я считаю, что сообщение инспекторы классифицируются как "расширяемость канала", которая, согласно этому сообщению, are поддерживается компактными рамками.
вы добавляете его в вызов с помощью:
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");
Если вы просто хотите добавить один и тот же заголовок ко всем запросам к сервису, вы можете сделать это без какого-либо кодирования!
Просто добавьте узел заголовки с необходимыми заголовками под узлом конечной точки в файле конфигурации клиента<client> <endpoint address="http://localhost/..." > <headers> <HeaderName>Value</HeaderName> </headers> </endpoint>
вот еще одно полезное решение для ручного добавления пользовательских заголовков HTTP в клиентский запрос WCF с помощью
ChannelFactory
в качестве прокси. Это должно быть сделано для каждого запроса, но достаточно как простая демонстрация, если вам просто нужно проверить свой прокси-сервер в процессе подготовки non-.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... }
это похоже на ответ 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();
var endpoint = new EndpointAddress(new Uri(RemoteAddress), new[] { AddressHeader.CreateAddressHeader("APIKey", "", "bda11d91-7ade-4da1-855d-24adfe39d174") });
вы можете указать пользовательские заголовки в MessageContract.
вы также можете использовать заголовки которые хранятся в файле конфигурации и будут скопированы allong в заголовке всех сообщений, отправленных клиентом/службой. Это полезно, чтобы легко добавить статический заголовок.
контекст привязки в .NET 3.5 может быть именно то, что вы ищете. Есть три из коробки: BasicHttpContextBinding, NetTcpContextBinding и WSHttpContextBinding. Контекстный протокол в основном передает пары ключ-значение в заголовке сообщения. Проверьте Управление Государством С Длительными Услугами статья в журнале MSDN.
Если я правильно понимаю ваше требование, простой ответ: вы не можете.
Это потому, что клиент службы WCF может быть создан любой третьей стороной, которая использует вашу службу.
если у вас есть контроль над клиентами вашего сервиса, вы можете создать базовый клиентский класс, который добавляет нужный заголовок и наследует поведение на рабочих классах.
это то, что сработало для меня, адаптировано из добавление заголовков HTTP в вызовы WCF
// Message inspector used to add the User-Agent HTTP Header to the WCF calls for Server public class AddUserAgentClientMessageInspector : IClientMessageInspector { public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel) { HttpRequestMessageProperty property = new HttpRequestMessageProperty(); var userAgent = "MyUserAgent/1.0.0.0"; if (request.Properties.Count == 0 || request.Properties[HttpRequestMessageProperty.Name] == null) { var property = new HttpRequestMessageProperty(); property.Headers["User-Agent"] = userAgent; request.Properties.Add(HttpRequestMessageProperty.Name, property); } else { ((HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name]).Headers["User-Agent"] = userAgent; } return null; } public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState) { } } // Endpoint behavior used to add the User-Agent HTTP Header to WCF calls for Server public class AddUserAgentEndpointBehavior : IEndpointBehavior { public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { clientRuntime.MessageInspectors.Add(new AddUserAgentClientMessageInspector()); } public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { } public void Validate(ServiceEndpoint endpoint) { } }
после объявления этих классов вы можете добавить новое поведение в свой клиент WCF следующим образом:
client.Endpoint.Behaviors.Add(new AddUserAgentEndpointBehavior());
это работает для меня
TestService.ReconstitutionClient _serv = новый TestService.TestClient();
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); }
немного поздно на вечеринку, но Juval Lowy обращается к этому точному сценарию в своем книги и связанный с ним ServiceModelEx библиотека.
в основном он определяет специализации ClientBase и ChannelFactory, которые позволяют указывать типобезопасные значения заголовка. Я предлагаю загрузить исходный код и посмотреть на классы HeaderClientBase и HeaderChannelFactory.
Джон