AJ's blog

January 31, 2015

WCF Policy – Part 8: Making the Information Available on the Client

Filed under: .NET, .NET Framework, C#, SOA, Software Architecture, Software Development, WCF — ajdotnet @ 4:37 pm

Our policy has its default behavior. All the information is collected, it just is not available to the developer yet. So let’s take care of that.

We already have the basics covered, namely we have an interface ITrackingInformation through which the application developer should have access to the information. All we need to do is to build a bridge between message inspectors and the application code.

On the client the application developer uses the generated client proxy class, thus we need to pass in the tracking information to that object. The class derives from ClientBase<TChannel> and thus inherits the property Endpoint of type ServiceEndpoint. This class in turn maintains a collection of endpoint behaviors. With a custom behavior which implements our interface, the developer has the gate to our policy. Going one step further, this behavior can also register a message inspector in IEndpointBehavior.ApplyClientBehavior, which utilizes the information passed in, instead of a temporary object, as we did when we implemented this last time.

The endpoint behavior is actually quite simple:

public class TrackingEndpointBehavior : IEndpointBehavior, ITrackingInformation
{
    public TrackingHeaders IncomingHeaders { get; private set; }
    public TrackingHeaders OutgoingHeaders { get; private set; }
    
    void IEndpointBehavior.ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        clientRuntime.MessageInspectors.Add(new TrackingClientMessageInspector(endpoint, this));
    }
    […]
}

And given the fact that I “kind of had this in mind”, the changes to the message inspector are also minor: We need an addition constructor and member for the information passed in, which is boilerplate enough. Additionally the method to get the tracking information object changes slightly:

private ITrackingInformation GetTrackingInformation()
{
    var tracking = _providedTrackingInformation ?? new TrackingInformation();
    return tracking;
}

The other code worked already against the interface and does not care where the tracking information object came from. I love it when a plan comes together.

There is one thing left: The contract behavior created during code generation is still in place and still registers its own message inspector. This is still necessary in cases where the application developer does not provide the above endpoint behavior, but hurts if he does. Luckily the contract behavior’s ApplyClientBehavior method is called after the endpoint behavior’s method. So all we need to do is to check:

void IContractBehavior.ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
    var endpointBehavior = endpoint.Behaviors.OfType<TrackingEndpointBehavior>().FirstOrDefault();
    if (endpointBehavior == null)
        clientRuntime.MessageInspectors.Add(new TrackingClientMessageInspector(endpoint));
}

And, finally, the application developer can provide the endpoint behavior and use it to pass additional tracking entries in or read the tracking entry collections after the call:

var client = new TestServiceReference.TestServiceClient();
var behavior = new TrackingEndpointBehavior();
behavior.OutgoingHeaders.TrackingEntries.Add(new TrackingEntry("my code", "just for fun"));
client.Endpoint.Behaviors.Add(behavior);

var response = client.Ping(“Ping text”);
var trackingEntries= behavior.IncomingHeaders.TrackingEntries;
[…]

So far for the client, next time, we will look at the server.

 

That’s all for now folks,
AJ.NET

Advertisements

Blog at WordPress.com.