22

Is there a way to specify global settings for Json.net?

The problem we're having is that it puts all DateTimes in UTC (rightly so). For legacy purposes, we want to default to Local time. I don't want to put the following code all over the place:

var settings = New JsonSerializerSettings();
settings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
JsonConvert.DeserializeObject(json, settings);
Vadim Ovchinnikov
  • 13,327
  • 5
  • 62
  • 90
Lodewijk
  • 2,380
  • 4
  • 25
  • 40

2 Answers2

36

So, this was added to Json.net 5.0 Release 5

JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
    DateTimeZoneHandling = DateTimeZoneHandling.Local
};

From the release notes:

Set once with JsonConvert.DefaultSettings in an application, the default settings will automatically be used by all calls to JsonConvert.SerializeObject/DeserializeObject, and JToken.ToObject/FromObject. Any user supplied settings to these calls will override the default settings.

Because there are cases where JSON should not be customized, e.g. a Facebook or Twitter library, by default JsonSerializer won’t use DefaultSettings, providing an opt-out for those frameworks or for places in your application that shouldn’t use default settings. To create a JsonSerializer that does use them there is a new JsonSerializer.CreateDefault() method.

Do note that when ASP.NET invokes Newtonsoft directly, e.g. in model binding or response formatting, it opts out of using these global default settings. To configure defaults used internally by ASP.NET see this answer by Andrei.

dbc
  • 104,963
  • 20
  • 228
  • 340
Lodewijk
  • 2,380
  • 4
  • 25
  • 40
  • 1
    It doesn't work in the case of setting a ContractResolver, I don't know why yet. It simply doesn't apply. JsonConvert.SerializeObject(obj, new JsonSerializerSettings { ContractResolver = new NHibernateContractResolver() }); – PandaWood Mar 06 '14 at 03:41
  • Yep, sorry, I tried JSON NET 5.05 and 6 - setting a global ContractResolver, as per the suggested code, does not work. The settings are not recalled on each subsequent call to JsonConvert.SerializeObject() – PandaWood Mar 06 '14 at 04:14
  • 1
    @PandaWood I found that setting a default contract resolver using this technique works with json.net in general, but does not work with Web API (version 5.2.2 at least) specifically. It seems like something in Web API's configuration overrides the default contract resolver and sets it's own. Of course, not sure if your use case was specific to Web API. – Jeremy Cook Jun 19 '15 at 16:38
  • 1
    @JeremyCook please see my answer – Andrei Jun 20 '17 at 00:47
14

Yes, indeed you can setup default Json.Net settings as Lodewijk explained. But Web API uses its own settings and you have to set them separately.

Web API (.NET Core 3.x and later)

In these versions Json.NET is not used by default. To use it, reference the Microsoft.AspNetCore.Mvc.NewtonsoftJson NuGet package and do:

services.AddControllers()
.AddNewtonsoftJson(options => 
{
    options.SerializerSettings.Converters.Add(nnew StringEnumConverter());
});

Web API (.NET Core 1.x and 2.x)

services.AddMvc(opts =>
{
    var jsonFormatter = (JsonOutputFormatter) opts.OutputFormatters
        .First(formatter => formatter is JsonOutputFormatter);
    jsonFormatter.PublicSerializerSettings.Converters.Add(new StringEnumConverter());
});

Web API (.NET Framework)

var config = GlobalConfiguration.Configuration;
config.Formatters.JsonFormatter.SerializerSettings.Converters
    .Add(new StringEnumConverter());

Default Global Settings

Also Json.NET now has an API to setup default global settings:

JsonConvert.DefaultSettings = () =>
{
    var settings = new JsonSerializerSettings();
    settings.Converters.Add(new StringEnumConverter());
    settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    return settings;
};
dbc
  • 104,963
  • 20
  • 228
  • 340
Andrei
  • 42,814
  • 35
  • 154
  • 218
  • This affects only processing on the boundaries of controller, afaik. So I think that it is not a proper answer. – Konstantin Aug 08 '17 at 19:00