Question

I've implemented a WCF Routing service; I would also like the service (or a similar WCF service) to transform the payload in a prescribed and uniform (content-agnostic) fashion. For example, the payload will always take the form Foo<T> and I would like to pass it on as Bar<T> in all cases. I'm happy for the transformation to be XSLT or programmatic. I don't care what happens to messages received that aren't of the type Foo<T>.

I wish to use WCF as it provides a lot of OOTB functionality (e.g. its support for numerous bindings). It's not practical to implement a WCF service with numerous boilerplate methods to transform each closed generic (Foo<Class1> -> Bar<Class1>; Foo<Class2> -> Bar<Class2>; etc), as this would require recompilation/redeployment every time a new message type was to be routed.

To the best of my knowledge, WCF doesn't handle open generics and WCF Routing doesn't facilitate content transformation OOTB. That said, System.ServiceModel.Routing.RoutingService obviously intercepts WCF calls in some non-specific form, so I was hoping to leverage the same pattern to achieve my goal. Can anyone please provide direction on how to do this (or indicate why it's not possible)?

Was it helpful?

Solution

As I suggested in my comments on the question, there is a solution to this using the IDispatchMessageInspector. Please find below an extremely dumbed-down version of what I ended up writing (easier than me posting the code for 20 classes). If anyone wants a full solution implementing this code in a significantly cleaner and more advanced manner, let me know and I'll put my demo up on CodeProject. For now, I'll presume you're happy with a snippet of the guts.

The Console commands can obvious be removed (they're just so you can debug if you're self-hosting).

    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
    {
        if (request == null || request.IsEmpty)
            return null;

        Console.WriteLine();
        Console.ForegroundColor = ConsoleColor.Green;
        Console.WriteLine(request);
        Console.ResetColor();

        // Load the request into a document.
        XPathDocument document;
        MemoryStream stream;
        using (stream = new MemoryStream())
        {
            using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(stream))
            {
                request.WriteMessage(writer);
                writer.Flush();
                stream.Position = 0L;
                document = new XPathDocument(stream);
            }
        }

        // Load the XSLT.
        XslCompiledTransform transformer = new XslCompiledTransform();
        transformer.Load("RequestTransformation.xslt");

        // Transform the document.
        byte[] transformedDocument;
        using (stream = new MemoryStream())
        {
            transformer.Transform(document, null, stream);
            transformedDocument = stream.ToArray();
        }

        // Construct new request from tranformed document.
        stream = new MemoryStream(transformedDocument);
        XmlReader reader = XmlReader.Create(stream);
        Message modifiedMessage = Message.CreateMessage(reader, int.MaxValue, request.Version);
        modifiedMessage.Properties.CopyProperties(request.Properties);
        request = modifiedMessage;

        Console.WriteLine();
        Console.ForegroundColor = ConsoleColor.Yellow;
        Console.WriteLine(new System.Text.UTF8Encoding(false).GetString(transformedDocument));
        Console.ResetColor();

        return null;
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top