I have a WCF service that is hosted in a Windows Service. Clients that using this service must pass an identifier every time they\'re calling service methods (because that i
If you want to add custom HTTP headers to every WCF call in an object oriented way, look no further.
Just as in Mark Good's and paulwhit's answer, we need to subclass IClientMessageInspector
to inject the custom HTTP headers into the WCF request. However, lets make the inspector more generic by accepting an dictionary containing the headers we want to add:
public class HttpHeaderMessageInspector : IClientMessageInspector
{
private Dictionary<string, string> Headers;
public HttpHeaderMessageInspector(Dictionary<string, string> headers)
{
Headers = headers;
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
// ensure the request header collection exists
if (request.Properties.Count == 0 || request.Properties[HttpRequestMessageProperty.Name] == null)
{
request.Properties.Add(HttpRequestMessageProperty.Name, new HttpRequestMessageProperty());
}
// get the request header collection from the request
var HeadersCollection = ((HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name]).Headers;
// add our headers
foreach (var header in Headers) HeadersCollection[header.Key] = header.Value;
return null;
}
// ... other unused interface methods removed for brevity ...
}
Just as in Mark Good's and paulwhit's answer, we need to subclass IEndpointBehavior
to inject our HttpHeaderMessageInspector
into our WCF client.
public class AddHttpHeaderMessageEndpointBehavior : IEndpointBehavior
{
private IClientMessageInspector HttpHeaderMessageInspector;
public AddHttpHeaderMessageEndpointBehavior(Dictionary<string, string> headers)
{
HttpHeaderMessageInspector = new HttpHeaderMessageInspector(headers);
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.ClientMessageInspectors.Add(HttpHeaderMessageInspector);
}
// ... other unused interface methods removed for brevity ...
}
The last part needed to finish our object oriented approach, is to create a subclass of our WCF auto-generated client (I used Microsoft's WCF Web Service Reference Guide to generate a WCF client).
In my case, I need to attach an API key to the x-api-key
HTML header.
The subclass does the following:
EndpointConfiguration
enum was generated to pass into the constructor - maybe your implementation won't have this)AddHttpHeaderMessageEndpointBehavior
to the client's Endpoint
behaviorspublic class Client : MySoapClient
{
public Client(string apiKey) : base(EndpointConfiguration.SomeConfiguration)
{
var headers = new Dictionary<string, string>
{
["x-api-key"] = apiKey
};
var behaviour = new AddHttpHeaderMessageEndpointBehavior(headers);
Endpoint.EndpointBehaviors.Add(behaviour);
}
}
Finally, use your client!
var apiKey = 'XXXXXXXXXXXXXXXXXXXXXXXXX';
var client = new Client (apiKey);
var result = client.SomeRequest()
The resulting HTTP request should contain your HTTP headers and look something like this:
POST http://localhost:8888/api/soap HTTP/1.1
Cache-Control: no-cache, max-age=0
Connection: Keep-Alive
Content-Type: text/xml; charset=utf-8
Accept-Encoding: gzip, deflate
x-api-key: XXXXXXXXXXXXXXXXXXXXXXXXX
SOAPAction: "http://localhost:8888/api/ISoapService/SomeRequest"
Content-Length: 144
Host: localhost:8888
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<SomeRequestxmlns="http://localhost:8888/api/"/>
</s:Body>
</s:Envelope>
Context bindings in .NET 3.5 might be just what you're looking for. There are three out of the box: BasicHttpContextBinding, NetTcpContextBinding, and WSHttpContextBinding. Context protocol basically passes key-value pairs in the message header. Check out Managing State With Durable Services article on MSDN magazine.
You add it to the call using:
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
}
And then, server-side you grab it using:
MessageHeaders headers = OperationContext.Current.IncomingMessageHeaders;
string identity = headers.GetHeader<string>("Identity", "http://www.my-website.com");
This works for me
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);
}
If I understand your requirement correctly, the simple answer is: you can't.
That's because the client of the WCF service may be generated by any third party that uses your service.
IF you have control of the clients of your service, you can create a base client class that add the desired header and inherit the behavior on the worker classes.
Here is another helpful solution for manually adding custom HTTP Headers to your client WCF request using the ChannelFactory
as a proxy. This would have to be done for each request, but suffices as a simple demo if you just need to unit test your proxy in preparation for non-.NET platforms.
// 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...
}