AJ's blog

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

Advertisement

1 Comment »

  1. Reblogged this on iReadable.

    Comment by Elliot Balynn — January 18, 2015 @ 6:22 pm


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: