ProfK ProfK - 6 months ago 15
JSON Question

How can I provide optional settings for my 'custom' JsonDotNetResult?

I have an alternate

JsonResult
, being the class below, to provide a better JSON serializer than the default for MVC Web Apps (irrelevant bits omitted):

public class JsonDotNetResult : JsonResult
{
public readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Arrays,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
ContractResolver = new CamelCasePropertyNamesContractResolver(),
Converters = new List<JsonConverter> { new StringEnumConverter() }
};

public override void ExecuteResult(ControllerContext context)
{
...
var response = context.HttpContext.Response;
...
response.Write(JsonConvert.SerializeObject(Data, Settings));
}
}


Then I have an overload for
Controller.Json
, declared as:

protected JsonResult Json(object data, string contentType, Encoding contentEncoding, JsonRequestBehavior behavior, JsonSerializerSettings settings = null)


but I don't have the existing default settings set in the
Settings
field of
JsonDotNetResult
, so if I pass in a new
JsonSerializerSettings
, with a few properties set by the caller, I will overwrite all the properties of the
Settings
object with the default values for
JsonSerializerSettings
, and with the new values provided by the caller. The latter being desired, the former I'm trying to avoid.

How can I pass in a subset of
JsonSerializerSettings
property values and apply them to the
Settings
object in
JsonDotNetResult
? My best (and first) effort is to loop through the properties of the default
Settings
object and compare them to property values on a new
JsonSerializerSettings
object passed by the user, and where the differ, set the value on
Settings
to the value supplied by the user.

Answer

I would define global default settings for JsonConvert in Global.asax.cs:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);

    JsonConvert.DefaultSettings = () => new JsonSerializerSettings
    {
        PreserveReferencesHandling = PreserveReferencesHandling.Arrays,
        ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
        ContractResolver = new CamelCasePropertyNamesContractResolver(),
        Converters = new List<JsonConverter> { new StringEnumConverter() }
    };
}

JsonConvert.DefaultSettings is a lambda function that creates default settings used by converter. When you supply your own setting the default one will get overridden. So, then whenever you want to change that settings just call

var settings = (JsonSerializerSettings)JsonConvert.DefaultSettings.Invoke();

to get new copy of default settings that you can modify as you need.

settings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;

That way you can remove readonly JsonSerializerSettings Settings = new JsonSerializerSettings from JsonDotNetResult because it will use default settings anyway:

public class JsonDotNetResult : JsonResult
{
    public override void ExecuteResult(ControllerContext context)
    {
        ...
        var response = context.HttpContext.Response;
        ...
        response.Write(JsonConvert.SerializeObject(Data));
    }
}

What I like in this method is that you have your default settings in one place so it keeps your code clean and easy to maintain.

Comments