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

January 24, 2015

WCF Policy – Part 7: Implementing the Default Behavior

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

Our policy demands that we read and manipulate the messages going in and out, on client and service. The WCF component designated for this demand is a message inspector, which is available in two flavors, designated by the interface: IClientMessageInspector for the client, and IDispatchMessageInspector for the service. Both interfaces provide two methods; one is called for the incoming message, the other for the outgoing message. The respective runtimes – ClientRuntime und DispatchRuntime – each maintain a collection of respective message inspector instances.

On the client the contract behavior created by our import extension can add the message inspector in IContractBehavior.ApplyClientBehavior, nothing more than a one-liner:

void IContractBehavior.ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
    clientRuntime.MessageInspectors.Add(new TrackingClientMessageInspector(endpoint));
}

On the server, our service behavior can do the same, only it needs to address all eligible endpoints:

void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
    foreach (ChannelDispatcher cd in serviceHostBase.ChannelDispatchers)
    {
        foreach (EndpointDispatcher ep in cd.Endpoints)
        {
            var inspector = new TrackingDispatchMessageInspector(ep);
            ep.DispatchRuntime.MessageInspectors.Add(inspector);
        }
    }
}

If the application developer calls a service method on the client proxy class, the WCF creates a message object for the resulting SOAP message. It the proceeds to call IClientMessageInspector.BeforeSendRequest on all message inspectors.

In this method our TrackingClientMessageInspector creates an ITrackingInformation object to maintain the information, creates the first tracking entry for sending the message, passes it to your header class, which will later serialize it as SOAP header, and adds it to the collection of headers. Finally it returns the ITrackingInformation object as correlation state:

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

object IClientMessageInspector.BeforeSendRequest(ref Message request, IClientChannel channel)
{
    // get headers
    var tracking = GetTrackingInformation();
    
    // add send information
    tracking.OutgoingHeaders.TrackingEntries.Add(new TrackingEntry(_thisClient, "Send Request to " + _calledService));
    
    // tracking entries header
    var trackingEntriesHeader = new TrackingEntriesHeader(tracking.OutgoingHeaders.TrackingEntries);
    request.Headers.Add(trackingEntriesHeader);
    
    // pass headers via correlation state
    return tracking;
}

Now the SOAP message makes its journey to the service, where the WCF will create a respective message object and call IDispatchMessageInspector.AfterReceiveRequest on all message inspectors there.

Our TrackingDispatchMessageInspector deserializes the SOAP header, puts the information in a ITrackingInformation object, adds its tracking entry for receiving the message, and, again, returns the ITrackingInformation object as correlation state.

private ITrackingInformation GetTrackingInformation()
{
    var extension = new TrackingInformation();
    return extension;
}

object IDispatchMessageInspector.AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
    // install operation extension
    var tracking = GetTrackingInformation();
    
    // tracking entries header
    var trackingEntriesHeader = TrackingEntriesHeader.ReadHeader(request.Headers);
    if (trackingEntriesHeader != null)
        tracking.IncomingHeaders.TrackingEntries.AddRange(trackingEntriesHeader.TrackingEntries);
    
    // add receive information
    tracking.IncomingHeaders.TrackingEntries.Add(new TrackingEntry(_thisService, "Received Request" ));
    
    // and pass on to outgoing headers
    tracking.OutgoingHeaders.TrackingEntries.AddRange(tracking.IncomingHeaders.TrackingEntries);
    
    // pass headers via correlation state
    return tracking;
}

The WCF proceeds to call the service method, the application developer provided. Afterwards the same process goes backwards for the reply. The WCF calls IDispatchMessageInspector.BeforeSendReply for all message inspectors. It also passes in the correlation state we returned earlier. Without this information we wouldn’t be able to link the two calls in case several requests came in in parallel.

Our message inspector adds the respective tracking entry, puts in in our header class, and is done:

void IDispatchMessageInspector.BeforeSendReply(ref Message reply, object correlationState)
{
    var tracking = (ITrackingInformation)correlationState;
    
    // add send information
    tracking.OutgoingHeaders.TrackingEntries.Add(new TrackingEntry(_thisService, "Send Reply"));
    
    // tracking entries header
    var trackingEntriesHeader = new TrackingEntriesHeader(tracking.OutgoingHeaders.TrackingEntries);
    reply.Headers.Add(trackingEntriesHeader);
}

The SOAP message is sent back to the client. There the WCF again creates a message object and calls IClientMessageInspector.AfterReceiveReply for all message inspectors, passing in the correlation state, similar to what we saw on the server.

Our message inspector deserializes the SOAP header, adds its own tracking entry, and we’re done:

void IClientMessageInspector.AfterReceiveReply(ref Message reply, object correlationState)
{
    var tracking = (ITrackingInformation)correlationState;
    
    // tracking entries header
    var trackingEntriesHeader = TrackingEntriesHeader.ReadHeader(reply.Headers);
    if (trackingEntriesHeader != null)
        tracking.IncomingHeaders.TrackingEntries.AddRange(trackingEntriesHeader.TrackingEntries);
    
    // add receive information
    tracking.IncomingHeaders.TrackingEntries.Add(new TrackingEntry(_thisClient, "Received Reply from " + _calledService));
}

That’s it.

Let recap that in context: The application developer has put a service behavior on his service. This has lead to a respective contract behavior on the client. And with what we just provided, the two of them are working together at runtime to create a protocol of calls at runtime.

The final topic we have to address is making the information available to the developer.

 

That’s all for now folks,
AJ.NET

January 18, 2015

WCF Policy – Part 6: Implementation Basics

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

We’ve come pretty far, but we haven’t done anything worthwhile yet.

As a reminder: Our tracking policy is pretty simple: Client and server should keep track of sending and receiving messages, and accumulate that information along a request/reply call as part of the SOAP call. In the end this should create a timing protocol of the complete call.

So far we’ve got the design part covered: The server announces the policy, the client recognizes it. The next major aspect is actually doing something. In this post I’m going to provide some basics we are going to need further on. Classes to maintain the tracking information, as well as SOAP related helpers.

For a single tracking entry:

public class TrackingEntry
{
    public DateTime TimeStamp { get; private set; }
    public string Source { get; private set; }
    public string Reason { get; private set; }
    […]
}

TrackingHeaders combines the information going to the SOAP headers of one message, in our case a collection of tracking entries:

public class TrackingHeaders
{
    public List<TrackingEntry> TrackingEntries { get; private set; }
    […]
}

Since we have incoming and outgoing information, an interface abstracts the two of them, complemented with a respective class:

public interface ITrackingInformation
{
    TrackingHeaders IncomingHeaders { get; }
    TrackingHeaders OutgoingHeaders { get; }
}

internal class TrackingInformation : ITrackingInformation
{
    public TrackingHeaders IncomingHeaders { get; private set; }
    public TrackingHeaders OutgoingHeaders { get; private set; }
    […]
}

In case you are wondering about this setup: It’s modeled after the MessageHeaders class containing the headers natively supported by the WCF, and the way they are made available in the Message class.

We are going to include the information in the SOAP message as SOAP header – we do not want it to interfere with the actual contract and content – thus we need a MessageHeader class that deals with serialization/deserialization. Unfortunately the class supports only serialization of data based on data contracts, which in turn do not support XML attributes. Therefore, if more efficient XML is desired, one needs to take serialization into his own hands. Writing the header can be done by overriding the respective method:

internal class TrackingEntriesHeader : BaseMessageHeader
{
    public IEnumerable<TrackingEntry> TrackingEntries { get; private set; }
    
    protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
    {
        foreach (var entry in TrackingEntries)
        {
            writer.WriteStartElement(NamespacePrefix, "Entry", Namespace);
            writer.WriteAttributeString("Source", entry.Source);
            writer.WriteAttributeString("TimeStamp", entry.TimeStamp.ToString("o"));
            writer.WriteAttributeString("Reason", entry.Reason);
            writer.WriteEndElement();
        }
    }
    […]
}

Reading the header includes looking it up, requesting a reader and actually reading it:

public static TrackingEntriesHeader ReadHeader(MessageHeaders headers)
{
    return (TrackingEntriesHeader)ReadHeader(headers, Defines.HeaderElementTrackingEntries, Defines.HeaderNamespace, ReadHeaderContents);
}

protected static TrackingEntriesHeader ReadHeader(MessageHeaders headers, string name, string ns, Func<XmlDictionaryReader, BaseMessageHeader> readHeaderContents)
{
    int headerIndex = headers.FindHeader(name, ns);
    if (headerIndex < 0)
        return null;
    
    // Get an XmlDictionaryReader to read the header content
    var reader = headers.GetReaderAtHeader(headerIndex);
    var header = readHeaderContents(reader);
    
    // NOTE: We must(!) remove ("consume") the header if MustUnderstand=1,
    // otherwise it will be considered "not understood" and an exception will be thrown.
    headers.RemoveAt(headerIndex);
    
    return header;
}

static BaseMessageHeader ReadHeaderContents(XmlDictionaryReader reader)
{
    reader.ReadStartElement(Defines.HeaderElementTrackingEntries, Defines.HeaderNamespace); // skip …
    var entries = new List<TrackingEntry>();
    while ((reader.LocalName == "Entry") && (reader.NamespaceURI == Defines.HeaderNamespace))
    {
        var entry = ReadEntry(reader);
        entries.Add(entry);
        
        reader.Read();
        if (reader.NodeType == XmlNodeType.EndElement)
            reader.ReadEndElement();
    }
    return new TrackingEntriesHeader(entries);
}

static TrackingEntry ReadEntry(XmlDictionaryReader reader)
{
    var source = reader.GetAttribute("Source");
    var timeStamp = reader.GetAttribute("TimeStamp");
    var message = reader.GetAttribute("Reason");
    var ts = DateTime.ParseExact(timeStamp, "o", null, DateTimeStyles.RoundtripKind);
    return new TrackingEntry(source, message, ts);
}

In case you’re wondering: Some of these methods reside in a separate base class, which I omitted to simplify things a bit; it will be included in the sample code, though. 

Now we have the bits and pieces we are going to need. In the next posts we’ll start using them to actually implement the policy.

 

That’s all for now folks,
AJ.NET

January 15, 2015

WCF Policy – Part 5: Addendum: Policy Support in WCF

Another addendum before we move on…

As MSDN states in regard to WS-Policy 1.2 and 1.5:

“WCF uses the WS-Policy specification together with domain-specific assertions to describe service requirements and capabilities.”

(In case you are wondering: you can choose the policy version for your service using configuration, namely the serviceMetadata element, policyVersion attribute; default is WS-Policy 1.2.)

Regarding WS-PolicyAttachment the claim is:

“WCF implements WS-PolicyAttachment to attach policy expressions at various scopes in Web Services Description Language (WSDL).”

Sounds great, doesn’t it? But if you read carefully, WCF “using” WS-Policy and “implementing” WS-PolicyAttachment to achieve something actually does not imply fully supporting it.

 

The one pitfall I have found is the way policy expressions are identified and referenced. WS-Policy supports two ways to identify policy expressions, either by a Name attribute, or by a wsu:Id attribute (as shown in part 2 of this series). wsu:Id is used to identify policies residing in the same XML document, Name becomes necessary for policies in separate XML documents, for example imported using wsdl:import. The pitfall I mentioned: WCF does not support policies in separate XML documents, i.e. policy references using the Name attribute.

Now, as long as you are working within WCF on both client and server, this will never be an issues. However if your policy is provided by a Java Metro service, there is a choice, as documented here. Example 19.1 works fine with WCF clients, examples 19.2 and following are not supported. Other technologies may provide similar options, or – even worse – be limited to the Name attribute.

It’s not as if Microsoft doesn’t know the standards, they explained it quite well in “Understanding Web Services Policy”, chapter 2.8, “Referencing Policy Expressions”. They also know about the issue. Unfortunately they are not going to do something about it:

“At this point of time WCF only supports policies included in the same WSDL file and identified via the wsu:ID attribute.
Unfortunately, we are not seeing large customer demand supporting policies residing in secondary WSDL documents, so I will be resolving this bug as "Wont Fix".”

Sic!

Having had to support both, .NET and Java, I ended up writing a little command line application, that downloads and patches the WSDL of services using the Name attribute…

 

That’s all for now folks,
AJ.NET

Create a free website or blog at WordPress.com.