oligofren oligofren - 11 months ago 69
ASP.NET (C#) Question

How do I use a custom formatter for json serialization

In the code below I am manually creating a json object that adheres to our standard json response object format, which is the same for both errors and actual responses:

data : { /*something*/ },
status : { httpCode : 123, message: "error message" }

How can I configure ASP.NET to do this formatting for me? It can obviously do so using the standard JSON and XML formatter when doing content negotiation, but the linked article only points to a page on Custom Formatters that is blank (and also for ASP.NET MVC which I am not using)...

I would also like for it to be able to set the returned http code in the response object (as shown below).

Current manual formatting of json

public class FooController : ApiController
/// <summary>
/// The return format for both real results and errors
/// is { data : { }, status : { httpCode : 123, message: "error message" }
/// We have moved the error serialization to StandardizedRestServiceExceptionFilter,
/// but was unable to generalize the processing of the output format for normal responses
/// That could be improved, possibly using a IMessageFormatter ?
/// </summary>
/// <param name="code"></param>
/// <returns></returns
public JObject Coverage(string code)
dynamic returnObject = new JObject();
dynamic statusObject = new JObject();
dynamic dataObject = new JObject();

JArray stores = StoresWithCoverage(code);
var hasCoverage = stores.Count > 0;
dataObject.coverage = hasCoverage;

returnObject.data = dataObject;
returnObject.status = statusObject;

statusObject.message = "";
statusObject.httpCode = 200;

return returnObject;

So in the above example I would like to be able to just return an Object of some kind with a
property and have ASP.NET do the actual formatting and serialization to JSON (if requested in the content negotiation).

Answer Source

One can either use prebuilt or custom Media Formatters using the ASP.NET Web API.

In this case, one could take the custom formatter from the link above as an example, and modify the JSON content wrapper to one's needs (here: using JSON.NET):

First you need to specify which content type you are supporting:

public CustomJsonFormatter()
    // Add the supported media type.
    SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));

Then you you need to implement your override of the WriteToStream method:

public override void WriteToStream(Type type, object value, Stream  writeStream, HttpContent content)
    using (var writer = new StreamWriter(writeStream, effectiveEncoding))
        using (JsonWriter jw = new JsonTextWriter(writer))
            dynamic returnObject = new JObject();
            dynamic status = new JObject();
            JObject data = (JObject)JToken.FromObject(value);

            status.httpCode = HttpContext.Current.HttpResponse.StatusCode;
            status.message = null;

            returnObject.data = data;
            returnObject.status = status;

            jw.Formatting = Formatting.Indented;

            JsonSerializer serializer = new JsonSerializer();
            // for customizing settings, like lower casing
            // attribute names, see http://stackoverflow.com/a/6288726/200987
            serializer.ContractResolver = new CamelCasePropertyNamesContractResolver()

            serializer.Serialize(jw, returnObject);

And finally one needs to say which type one support transforming, register this formatter with ASP.NET, and some other minor (and usually non-required) modifications. Refer to the articles below for how to do this, as well as how serialization, http status codes and content negotiation works and can be customized.