Как добавить настраиваемый HTTP-заголовок для каждого вызова WCF?
У меня есть служба WCF, размещенная в службе Windows. Клиенты, использующие эту службу, должны передавать идентификатор каждый раз, когда они вызывают методы службы (поскольку этот идентификатор важен для того, что должен делать вызываемый метод). Я подумал, что это хорошая идея, чтобы как-то поместить этот идентификатор в информацию заголовка WCF.
Если это хорошая идея, как я могу автоматически добавить идентификатор в информацию заголовка. Другими словами, всякий раз, когда пользователь вызывает метод WCF, идентификатор должен автоматически добавляться в заголовок.
ОБНОВЛЕНИЕ: Клиенты, использующие службу WCF, являются приложениями Windows и приложением Windows Mobile (с использованием Compact Framework).
- Увеличение значения тайм-аута в службе WCF
- Событие запуска приложения WCF
- Ошибка пользовательского исключения веб-службы WCF для клиента
- Как включить трассировку WCF?
- Где хранить данные для текущего вызова WCF? Безопасен ли ThreadStatic?
- Существующее соединение было принудительно закрыто удаленным хостом - WCF
- Формат тела веб-службы RESTful
- HTTP не смог зарегистрировать URL http: // +: 8000 / HelloWCF /. У вашего процесса нет прав доступа к этому пространству имен
- Получение IP-адреса клиента в WCF 3.0
- Служба WCF, как увеличить таймаут?
- Несоответствие ContractFilter при исключении EndpointDispatcher
Преимущество этого заключается в том, что оно применяется к каждому вызову.
Создайте class, который реализует 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 ко всем сообщениям запроса. Я использую это в нескольких моих клиентах. Вы также можете сделать то же самое на стороне обслуживания, выполнив IDispatchMessageInspector .
Это то, что вы имели в виду?
Обновление: я нашел этот список функций WCF, поддерживаемых компактной картой. Я считаю, что инспекторы сообщений classифицируются как «Расширение канала», которые, согласно этому сообщению, поддерживаются компактной инфраструктурой.
Вы добавляете его к вызову, используя:
using (OperationContextScope scope = new OperationContextScope((IContextChannel)channel)) { MessageHeader header = new MessageHeader ("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("Identity", "http://www.my-website.com");
Если вы просто хотите добавить один и тот же заголовок ко всем запросам службы, вы можете сделать это без какой-либо кодировки!
Просто добавьте узел заголовков с требуемыми заголовками под узлом конечной точки в файле конфигурации клиента
Value
Вот еще одно полезное решение для ручного добавления пользовательских заголовков 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... }
Это похоже на ответ 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 .
Вы также можете использовать заголовки
Контекстные привязки в .NET 3.5 могут быть именно тем, что вы ищете. Есть три варианта: BasicHttpContextBinding, NetTcpContextBinding и WSHttpContextBinding. Контекстный протокол в основном передает пары ключ-значение в заголовке сообщения. Посмотрите статью « Управление государством с долговременными службами» в журнале MSDN.
Если я правильно понимаю ваше требование, простой ответ таков: вы не можете.
Это связано с тем, что клиент службы WCF может генерироваться любой третьей стороной, использующей вашу службу.
Если вы контролируете клиентов своей службы, вы можете создать базовый клиентский class, который добавит желаемый заголовок и наследует поведение на рабочих classах.
Это то, что сработало для меня, адаптировано из « Добавление заголовков 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) { } }
После объявления этих classов вы можете добавить новое поведение к клиенту WCF следующим образом:
client.Endpoint.Behaviors.Add(new AddUserAgentEndpointBehavior());
Это работает для меня
TestService.ReconstitutionClient _serv = new 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); }
Немного поздно, но Юваль Лоуи описывает этот точный сценарий в своей книге и соответствующей библиотеке ServiceModelEx .
В основном он определяет специализации ClientBase и ChannelFactory, которые позволяют указывать значения заголовков, безопасных для типов. Я рекомендую загрузить исходный код и посмотреть classы HeaderClientBase и HeaderChannelFactory.
Джон