Search code examples
c#.netwebember.jsjson-api

How to setup JsonApiSerializer as default input and output seriliazers C# .NET Core 3+


I've been trying to setup JsonApiSerializer (https://github.com/codecutout/JsonApiSerializer) as the default serializer for both input and output so I can have an json:api compliant .NET server for an Ember application with Ember Data.

I have succesfully setup the output serializer by writing the following code to the Startup.cs file:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.AddDbContext<Context>(options => options.UseSqlServer(Configuration.GetConnectionString("myDb")));

            var sp = services.BuildServiceProvider();
            var logger = sp.GetService<ILoggerFactory>();
            var objectPoolProvider = sp.GetService<ObjectPoolProvider>();

            services.AddMvc(opt =>
            {
                var serializerSettings = new JsonApiSerializerSettings();
**
                var jsonApiFormatter = new NewtonsoftJsonOutputFormatter(serializerSettings, ArrayPool<Char>.Shared, opt);
                opt.OutputFormatters.RemoveType<NewtonsoftJsonOutputFormatter>();
                opt.OutputFormatters.Insert(0, jsonApiFormatter);
**
                var mvcNewtonsoftSettings = new MvcNewtonsoftJsonOptions();

                var jsonApiInputFormatter = new NewtonsoftJsonInputFormatter(logger.CreateLogger<NewtonsoftJsonInputFormatter>(), serializerSettings, ArrayPool<Char>.Shared, objectPoolProvider, opt, mvcNewtonsoftSettings);
                opt.InputFormatters.RemoveType<NewtonsoftJsonInputFormatter>();
                opt.InputFormatters.Insert(0, jsonApiInputFormatter);
                //opt.InputFormatters.OfType<NewtonsoftJsonInputFormatter>().FirstOrDefault().SupportedMediaTypes.Add("application/vnd.api+json");

            }).AddNewtonsoftJson();
        }

But the Input part isn't working yet!

I've been triyng to receive code from a Ember application that follows this structure:

{
  "data": 
  {
    "type": "manufacturer",
    "name": "Fabricante 1",
    "relationships": {
      "products": {
        "data": [
          {
            "type": "product",
            "id": "1"
          },
          {
            "type": "product",
            "id": "2"
          }
        ]
      }
    }
  }
}

The binding model of the .NET server for POSTing a manufacturer is like this:

public class CreateManufacturerBindingModel
    {
        public string Type { get; set; } = "manufacturer";
        public string Name { get; set; }
        public AssignProductBidingModel[] Products { get; set; }
    }

public class AssignProductBidingModel
    {
        public string Type { get; set; } = "product";
        public int Id { get; set; }
    }

I've been trying out some variations of those codes for a while and all I can get is Null values for "Name" and "Products" attributes of the CreateManufacturerBindingModel

Does anyone has any clue of why I keep on getting null values at the .NET server?

Thank you for your attention!


Solution

  • ASP.NET Core 3.1 will use the System.Text.Json serializers by default. The JsonApiSerializer you are attempting to use requires Newtonsoft. You can use Newtonsoft in the project by installing the following nuget package. (don't use latest 5.0.0 version as it requires net5.0)

    Install-Package Microsoft.AspNetCore.Mvc.NewtonsoftJson -Version 3.1.10`
    

    You can then configure the serializer as below. It does not allow you to replace the entire SerizlierSettings but the JsonApiSerializerSettings only sets a few properties so we can set them directly

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers().AddNewtonsoftJson(opts =>
        {
            opts.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
            opts.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
            opts.SerializerSettings.ContractResolver = new JsonApiContractResolver(new ResourceObjectConverter());
            opts.SerializerSettings.DateParseHandling = DateParseHandling.None;
        });
    }
    

    Finally you will need to update your model so that it contains an Id field. This is how the JsonApiSerializer identifies resource objects

    public class CreateManufacturerBindingModel
    {
        public string Type { get; set; } = "manufacturer";
    
        // Need to have an ID property
        public string Id { get; set; }
    
        public string Name { get; set; }
        public AssignProductBidingModel[] Products { get; set; }
    }
    

    With that in place it should start serializing and deserializing your objects as JsonApi objects