How to: c# XML InfoSet to JSON

191 views Asked by At

So WCF takes a JSON, and for whatever reason translates that to an XML Infoset (see: https://stackoverflow.com/a/5684703/497745). It then reads back this XML Infoset internally using the JsonReaderDelegator (see: https://referencesource.microsoft.com/#System.Runtime.Serialization/System/Runtime/Serialization/Json/JsonReaderDelegator.cs,c0d6a87689227f04).

I am doing some very in-depth modification of the WCF execution flow, and I need to reverse the XML Infoset back to the original JSON.

Is there a library either in .NET or external that can take the XML Infoset generated by WCF and convert that back to its original JSON?

1

There are 1 answers

0
Ayo I On BEST ANSWER

Found an answer that works in my scenario with some limited modifications.

This article: https://blogs.msdn.microsoft.com/carlosfigueira/2011/04/18/wcf-extensibility-message-inspectors/ explains how to log the JSON that originally came in to WCF, even though it is only exposed as an XML InfoSet. This was the key insight. Specifically, look at its MessageToString implementation.

Below is the relevant portion of my code, based on the implementation of MessageToString in the above link, running within a class internal class MessageFormatInspector : IDispatchMessageInspector, IEndpointBehavior that I have written to inject into the WCF stack:

public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
   ...
   var s = GetJsonFromMessage(request);
   ...
}

private static string GetJsonFromMessage(ref Message request)
{

    using (MemoryStream ms = new MemoryStream())
    {
        using (XmlDictionaryWriter writer = JsonReaderWriterFactory.CreateJsonWriter(ms))
        {
            request.WriteMessage(writer);
            writer.Flush();
            string json = Encoding.UTF8.GetString(ms.ToArray()); //extract the JSON at this point

            //now let's make our copy of the message to support the WCF pattern of rebuilding messages after consuming the inner stream (see: https://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.idispatchmessageinspector.afterreceiverequest(v=vs.110).aspx and https://blogs.msdn.microsoft.com/carlosfigueira/2011/05/02/wcf-extensibility-message-formatters/)
            ms.Position = 0; //Rewind. We're about to make a copy and restore the message we just consumed.

            XmlDictionaryReader reader = JsonReaderWriterFactory.CreateJsonReader(ms, XmlDictionaryReaderQuotas.Max); //since we used a JsonWriter, we read the data back, we need to use the correlary JsonReader.

            Message restoredRequestCopy = Message.CreateMessage(reader, int.MaxValue, request.Version); //now after a lot of work, create the actual copy
            restoredRequestCopy.Properties.CopyProperties(request.Properties); //copy over the properties
            request = restoredRequestCopy;
            return json;
        }
    }
}

Unfortunately, the above code only works within the context of a WCF message inspector.

However, it is able to take an XMLDictionary, which has the XML InfoSet, and to using WCF's own built in JsonWriter to reverse the conversion WCF did and emit the original JSON.

I hope this helps someone save some time in the future.