Francis Ducharme
Francis Ducharme

Reputation: 4987

Modifying JSON output

I have a Web API method returning a List<AttributeCollection>. AttributeCollection is kind of a list of, obviously, attributes with values for each attributes (in this case fetched by the CRM 2011 SDK).

Here is the JSON that the method returns:

[
    [
        {
            "Key": "mobilephone",
            "Value": "(430) 565-1212"
        },
        {
            "Key": "firstname",
            "Value": "John"
        }
    ],
    [
        {
            "Key": "mobilephone",
            "Value": "(430) 565-1313"
        },
        {
            "Key": "firstname",
            "Value": "Mark"
        }
    ]
]

Now, the first pair of brackets are a visual representation of the List, and then you have many pairs of brackets ([]) for each AttributeCollection.

I want to get rid of the first pair of brackets, replace it with a top level element name (ie: allAttributes) and then all items following.

I am overidding the WriteToStreamAsync method of JsonMediaTypeFormatter

public override System.Threading.Tasks.Task WriteToStreamAsync(Type type, object value, System.IO.Stream writeStream, HttpContent content, TransportContext transportContext)
{
    if ((typeof(IEnumerable<AttributeCollection>).IsAssignableFrom(type)))
    {
        //anything I could do here ?
    }


    return base.WriteToStreamAsync(type, value, writeStream, content, transportContext);
        } 

I thought of manipulating the JSON string itself, but it doesn't seem accessible from there.

Any ideas ?

Thanks.

Upvotes: 0

Views: 138

Answers (1)

carlosfigueira
carlosfigueira

Reputation: 87228

If you want to do that on the formatter itself, you may want to write the wrapping code to the writeStream, as in the code below (tested in Notepad):

public override async Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
{
    if ((typeof(IEnumerable<AttributeCollection>).IsAssignableFrom(type)))
    {
        var list = (IEnumerable<AttributeCollection>)value;
        byte[] headerBytes = Encoding.UTF8.GetBytes("{\"allAttributes\":");
        byte[] footerBytes = Encoding.UTF8.GetBytes("}");
        writeStream.Write(headerBytes, 0, headerBytes.Length);
        foreach (var item in list)
        {
            await base.WriteToStreamAsync(item.GetType(), item, writeStream, content, transportContext);
        }

        writeStream.Write(footerBytes, 0, footerBytes.Length);
    }
    else
    {
        return await base.WriteToStreamAsync(type, value, writeStream, content, transportContext);
    }
}

Another alternative would be to create a wrapping class and serialize it:

public class MyWrappingClass
{
    public IEnumerable<AttributeCollection> allAttributes { get; set; }
}

public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
{
    if ((typeof(IEnumerable<AttributeCollection>).IsAssignableFrom(type)))
    {
        var list = (IEnumerable<AttributeCollection>)value;
        var obj = new MyWrappingClass { allAttributes = list };
        return base.WriteToStreamAsync(obj.GetType(), obj, writeStream, content, transportContext);
    }
    else
    {
        return base.WriteToStreamAsync(type, value, writeStream, content, transportContext);
    }
}

Upvotes: 1

Related Questions