如何将自定义HTTP标头添加到每个WCF调用?
我有一个Windows服务托pipe的WCF服务。 使用此服务的客户端在每次调用服务方法时都必须传递一个标识符(因为该标识符对被调用的方法应该这样做很重要)。 我认为这是一个好主意,把这个标识符的WCF头信息。
如果这是一个好主意,我怎么能自动添加标识符到标题信息。 换句话说,只要用户调用WCF方法,标识符必须自动添加到标题中。
更新:使用WCF服务的客户端都是Windows应用程序和Windows Mobile应用程序(使用Compact Framework)。
这样做的好处是它适用于每一个电话。
创build一个实现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; }
然后创build将消息检查器应用于客户端运行时的端点行为。 您可以通过属性或通过使用行为扩展元素的configuration来应用行为。
以下是如何将HTTP用户代理标题添加到所有请求消息的一个很好的示例 。 我在我的一些客户中使用这个。 您也可以通过实现IDispatchMessageInspector在服务端执行相同的操作。
这是你想到的吗?
更新:我发现这个紧凑框架支持的WCFfunction列表 。 我相信信息检查员被归类为“渠道扩展性”,根据这个post,这个框架是支持的。
您使用以下方式将其添加到呼叫中:
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");
如果你只是想添加相同的头到服务的所有请求,你可以做任何编码!
只需在您的客户端configuration文件中的端点节点下添加头部节点和所需的头部
<client> <endpoint address="http://localhost/..." > <headers> <HeaderName>Value</HeaderName> </headers> </endpoint>
这里是另一个有用的解决scheme,即使用ChannelFactory
作为代理,手动向客户端WCF请求添加自定义HTTP头。 这将不得不为每个请求完成,但是如果您只需要testing代理以准备非.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中指定自定义标题。
您还可以使用存储在configuration文件中的<endpoint>头文件,并将其全部复制到由客户机/服务发送的所有消息的头文件中。 这是很有用的添加一些静态头容易。
.NET 3.5中的上下文绑定可能就是你正在寻找的东西。 有三个开箱即用:BasicHttpContextBinding,NetTcpContextBinding和WSHttpContextBinding。 上下文协议基本上传递了消息头中的键值对。 查看MSDN杂志上的“ 耐用服务pipe理状况”文章。
如果我正确理解你的要求,简单的答案是:你不能。
这是因为WCF服务的客户端可能由任何使用您的服务的第三方生成。
如果您可以控制服务的客户端,则可以创build基类客户端类,以添加所需的标头并在工作类上inheritance该行为。
这是对我来说,适应从添加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());
晚会有点晚,但Juval Lowy在他的书和相关的ServiceModelEx库中解决了这个确切的情况。
基本上他定义了ClientBase和ChannelFactory特化,允许指定types安全的标头值。 我build议下载源代码并查看HeaderClientBase和HeaderChannelFactory类。
约翰
这对我有用
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); }