Reputation: 1822
I am calling a WCF service hosted in IIS over HTTP, using basicHttpBinding
. In order to pass validation on the server, a custom header value must be passed, computed from the HTTP request itself (headers and body if present).
I can get most of the information from the call using a client message inspector (System.ServiceModel.Dispatcher.IClientMessageInspector
) custom endpoint behavior on the proxy (System.ServiceModel.Description.IEndpointBehavior
), and then accessing the httpRequest
header of the message object.
However, getting the message contents that are serialized to send across the wire don't appear to be immediately or obviously available. I can get the message itself, however, that's stored in an XmlSerializer, which doesn't make it available in the same format as how it will be sent over the wire.
Is there a way to access this value? Perhaps another inspector or behavior that can be injected, so that it is invoked at the time the channel binding is opened or accessed?
Upvotes: 3
Views: 2921
Reputation: 7320
You have to implement a custom IDispatchMessageInspector
, and inject it in an IOperationBehavior
or IEndpointBehavior
attribute. (in the ApplyDispatchBehavior()
method)
In the AfterReceiveRequest()
method of an IDispatchMessageInspector
, you can get the message body only by copying it (it's invalid once accessed) :
private String GetRequestBody(ref Message message)
{
MessageBuffer buffer = message.CreateBufferedCopy(Int32.MaxValue);
message = buffer.CreateMessage();
String xml = null;
try
{
var copy = buffer.CreateMessage();
var dicReader = copy.GetReaderAtBodyContents();
xml = dicReader.ReadOuterXml();
}
catch (Exception e)
{
}
return xml;
}
But if you just want to find a header value, you can simply get it with :
private String TryGetHeader(Message request, String headerName)
{
if (request.Headers.FindHeader(headerName, "HeaderMessageNamespace") != -1)
return request.Headers.GetHeader<String>(headerName, "HeaderMessageNamespace");
return null;
}
Create an attribute like this one, and put it on the method you want to track in your WCF service :
public class MyOperationBehaviorAttribute : Attribute, IOperationBehavior
{
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
if (dispatchOperation.Parent.MessageInspectors.OfType<MyMessageInspector>().Any() == false)
dispatchOperation.Parent.MessageInspectors.Add(new MyMessageInspector());
}
[...]
}
and implements the inspector like this :
public class MyMessageInspector : IDispatchMessageInspector
{
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
var result = TryGetHeader(request, "name");
return null;
}
[...]
}
AND for the client side :
You have to inject the behavior just after the service instantiation. With a MyServiceClient of type ClientBase, and a IEndpointBehavior myBehavior :
((ClientBase<ISomething>)service).Endpoint.Behaviors.Add(myBehavior);
with
public class MyBehavior : IEndpointBehavior
{
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(new MyMessageInspector());
}
[...]
}
Upvotes: 3