11

Context

In some of my class in an ASP.NET project serialize/deserialize JSON I suppose using the static JsonConvert... methods are not the best option, neither using new with a hardcoded class

Question

Would I inject something in the constructor? Do I have to define my custom simple interface for this purpose, or is there any convention/built in concept how to not hardcode types?

abatishchev
  • 98,240
  • 88
  • 296
  • 433
g.pickardou
  • 32,346
  • 36
  • 123
  • 268

3 Answers3

5

If it helps, ASP.NET Core is abstracting the JSON serializer itself in some places. For example, within Razor views (both views and pages), you can use Json.Serialize() to serialize stuff into the body. This uses the IJsonHelper to provide an abstracted access to the serialization, while using all the pre-configured settings from the serializer (ensuring a consistent output).

In 2.2, the underlying JsonHelper uses the JsonOutputFormatter to actually provide access to the serializer. Both the IJsonHelper and the JsonOutputFormatter are available through dependency injection, so you can inject those anywhere if you need them.

In 3.0, the team is removing the direct dependency on Newtonsoft.Json and introduces a proper abstraction themselves. The IJsonHelper is still around though. By default, Newtonsoft.Json will not around though, so if you depend on that (e.g. because you are using it statically), then you will have to add a dependency yourself (and maybe switch ASP.NET Core back to use it too).

When you want to deserialize, the IJsonHelper will not help you, and there is no component around that will give you direct access to the deserializer. In those cases, you can always create a JsonSerializer yourself. You can get the serializer settings from DI:

IOptions<MvcJsonOptions> mvcJsonOptions // get through DI

var serializer = JsonSerializer.Create(mvcJsonOptions.Options.SerializerSettings);

That uses the globally configured serialization settings from the framework.

Usually, just using the JsonConvert static would be fine too. In general though, you sould try to avoid having to serialize and deserialize stuff yourself. The framework will already take care of that for you in various places where data gets in or out. So depending on your use case, there might already be an automatism to convert between JSON.

poke
  • 369,085
  • 72
  • 557
  • 602
  • While options called `MvcJsonOptions` it seems that it works only with `services.AddMvc()` call. But how to make it with `services.AddControllers().AddJsonOptions(...)`? – Ircover Mar 05 '20 at 13:41
  • `AddJsonOptions(...)` is for `System.Text.Json`. You need `AddNewtonsoftJson(...)` for `Newtonsoft.Json` – ThomasDC Aug 18 '20 at 09:11
  • Thanks a lot! This is so helpful !! – Kaz-LA Nov 04 '20 at 21:13
3

Personally, I wouldn't really bother about abstracting a service such as a JSON serializer. Not all statics are wrong and not everything has to be abstracted in a service, except if it's highly expected you want to swap out implementations or create mocks for testing. Otherwise I'd suggest to focus on the business logic of your application and create abstractions only if they're necessary and provide value for the application's design and testability.

Henk Mollema
  • 44,194
  • 12
  • 93
  • 104
  • 1
    Thanks. I think a json serializer is typically a component what you want to plug in/change with one line of code for your app, either because you discover a limitation or just because to examine the performance improvement. Anyway if the built in serializer is sooo trusted... that we know we never want to change it... – g.pickardou May 20 '19 at 08:35
  • Valid point. However, in the specific case of a JSON serializer Json.NET has been the de facto serializer for many years now. Recently the .NET team started developing their own serializer which will ship in the box in .NET Core 3.0. If you really care about performance you might consider switching, but it less feature-rich as Newtonsoft.Json. Secondly, abstracting a service might also limit the features you can use without creating a leaky abstraction (e.g. passing a specific options object to the serialize method). – Henk Mollema May 20 '19 at 09:05
  • I'd say abstracting the serializer is good for unit testing. You just skip this part in tests, pass there fake data. It is much easier to write nice unit tests with abstracted serializer than with the real one in a static class. – Al Kepp Feb 08 '23 at 10:52
2

This isn't JSON serialization specific. As with every static class, you can't apply an interface to it (let alone a third-party class). See for example Dependency injection with a static logger, static helper class.

So you'll need to write your own wrapper class and inject that:

public interface IJsonSerializer
{
    string SerializeObject(object o);
    T DeserializeObject<T>(string json);
}

public class NewtonsoftJsonSerializer : IJsonSerializer
{
    public string SerializeObject(object o)
    {
        return Newtonsoft.Json.JsonConvert.SerializeObject(o);
    }

    public T DeserializeObject<T>(string json)
    {
        return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(json);
    }
}
CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • Thanks. I am aware, that my idea of creating the interface for DI is not serialization specific. I also knew how to do that. I was asking is there any built in / convention, or myself have to do that. (it could be also a question: is it recommended to do this in this particular case, or just go with the static JSonConvert) – g.pickardou May 20 '19 at 08:39