Create API With ASP.NET Core - Day Four - Working with Serializer Settings And Content Negotiation In ASP.NET Core API

Introduction

This article of the series “Web API with ASP.NET Core” will focus on topics like serializer strings and content negotiation. We learned how to deal with HTTP Status Codes and return sub resources in ASP.NET Core in last article and paused at Serializer Settings. We’ll continue to explore the importance of status codes and practical examples as well. We’ll also explore resource creation and returning the child resources as well in this article. We can use the same source code as we got at the completion of last article of the series.

RoadMap

We’ll follow a roadmap to learn and cover all the aspects of ASP.NET Core in details. Following is the roadmap or list of articles that will cover the entire series.

ASP.NET Core

  1. Create API with ASP.Net Core (Day 1): Getting Started and ASP.NET Core Request Pipeline
  2. Create API with ASP.Net Core (Day 2): Create an API and return resources in ASP.NET Core
  3. Create API with ASP.Net Core (Day 3): Working with HTTP Status Codes and returning sub resources in ASP.NET Core API
  4. Create API with ASP.Net Core (Day 4): Working with Serializer Settings and Content Negotiation in ASP.NET Core API
  5. Create API with ASP.Net Core (Day 5): Understanding Resources in ASP.NET CORE API
  6. Create API with ASP.Net Core (Day 6): Inversion of Control and Dependency Injection in ASP.NET CORE API
  7. Create API with ASP.Net Core (Day 7): Getting Started with Entity Framework Core
  8. Create API with ASP.Net Core (Day 8): Entity Framework Core in ASP.NET CORE API

Serializer Settings in ASP.NET Core API

By default, ASP.NET Core uses JSON for serialization and de-serialization, but the best thing is that we can also configure this in our code. If we open the source code we covered in last article, we used ConfigureServices method in the startup class to configure the services use be the container, in the similar way we can configure for MVC.

ASP.NET Core

We can add JSON options to the added MVC service.

ASP.NET Core

Since the AddJsonOptions method expects an action, we supply a lambda expression there as options parameter through which we can easily access the serializer settings as shown in above image. We fetch the contract resolver as we’ll override the default settings of naming strategy. The line var resolver = opt.SerializerSettings.ContractResolver as DefaultContractResolver; takes out the contract resolver and cast ot to the default contract resolver, we can now override its NamingStrategy property and mark it to null.

So now, it should not typically follow that lower letters convention, which it followed by default. We used DefaultContractResolver class which is the part of Newtonsoft.Json.Serialization, so we’ll have to add the namespace for it as well. The code will look like as below.
  1. public void ConfigureServices(IServiceCollection services)  
  2.     {  
  3.       services.AddMvc().AddJsonOptions(opt =>  
  4.       {  
  5.         if (opt.SerializerSettings.ContractResolver != null)  
  6.         {  
  7.           var resolver = opt.SerializerSettings.ContractResolver as DefaultContractResolver;  
  8.           resolver.NamingStrategy = null;  
  9.         }  
  10.       });  
  11.     }  

Now, let’s test this with Postman. In the last request, we got the json properties in lower case letters as shown below,

ASP.NET Core

Now, run the application and make a request for the same API from postman as consumer.

ASP.NET Core

Now, we get the JSON properties in capital letters i.e. overridden by our implementation. This implementation is on a need basis or based on the kind of JSON the consumer wants. Here comes the concept of content negotiation where response is sent based on consumers request parameters.

Content Negotiation and Formatters in ASP.NET Core API

Content negotiation is one of the important concepts when we develop an API. This enables an API to select best representation for a desired response when there are more than one representations available. Suppose we build an API for multiple consumers and clients we are not sure that whether all the clients would be able to consume the default representation that an API sends in the form JSON. Some consumers may expect XML as a response or any other format, in that case it would be hard for the consumers to understand and work with JSON instead of a XML.

There is always an option to the consumer to send a request for a specific format by specifying the requested media type in the Accept header. For e.g. if in the accept header, the requested format is XML, the API should send the response in XML format and if it is JSON, the API should send the response in JSON format. If there is no header specified, then API can take liberty to send the response in the default format that it has for e.g. JSON in our case. ASP.NET Core also supports this functionality via output formatters. Output formatter, as the name suggests mostly deals with the output. The consumer in that case can request any specific type of output that it wants by setting the accept header to request media type such as Application/JSON or Application/XML.

It also works with the input formats in a way that suppose there is a POST request to an API for creating a resource, the input media type and the content that comes along with the request is then identified by content-type header in the request. Let’s cover this with practical implementations. Let’s try to request the list of employees with the JSON accept header. So, we’ll set Header key as “Accept” and Value as “application/json”, and we get JSON as shown below.
ASP.NET Core

Now, make a request with accepting header application/xml, we still get JSON.

ASP.NET Core

But ideally, the API should return XML. Let’s see how we can configure our service to return the same. If we go to the Startup class’s ConfigureService method, we have an option to add MvcOptions to the service, which in turn has options to add input and output formatters.

ASP.NET Core

ASP.NET Core

If we need to use the Xml Output formatter, we’ll have to install a nugget package named Microsoft.AspNetCore.MVC.Formatters.Xml as shown below. So right click on the project, go to manage nugget packages and search online for this package and install it.

ASP.NET Core

Now if we can add the XML output formatter as shown in following code,
  1. services.AddMvc()  
  2. .AddMvcOptions(opt => opt.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()));  

Similarly Input formatters can also be added with XmlDataContractSerializerInputFormatter. So, build the solution, run the project and then now again try to request the employees list.

First with default or json formatter, we get JSON as shown below.

ASP.NET Core

And now with the Xml accept header we get XML as shown below.

ASP.NET Core

Hence now a consumer can request the response in desired format and our API is capable of delivering that as well.

Our code for Startup class looks like the following one now.

  1. using Microsoft.AspNetCore.Builder;  
  2. using Microsoft.AspNetCore.Hosting;  
  3. using Microsoft.Extensions.DependencyInjection;  
  4. using Microsoft.Extensions.Logging;  
  5. using Microsoft.AspNetCore.Mvc.Formatters;  
  6.   
  7. namespace EmployeeInfo.API  
  8. {  
  9.   public class Startup  
  10.   {  
  11.     // This method gets called by the runtime. Use this method to add services to the container.  
  12.     // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940  
  13.     public void ConfigureServices(IServiceCollection services)  
  14.     {  
  15.       services.AddMvc()  
  16.         .AddMvcOptions(opt => opt.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()));  
  17.       //.AddJsonOptions(opt =>  
  18.       //{  
  19.       //  if (opt.SerializerSettings.ContractResolver != null)  
  20.       //  {  
  21.       //    var resolver = opt.SerializerSettings.ContractResolver as DefaultContractResolver;  
  22.       //    resolver.NamingStrategy = null;  
  23.       //  }  
  24.       //});  
  25.     }  
  26.   
  27.     // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.  
  28.     public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)  
  29.     {  
  30.       loggerFactory.AddConsole();  
  31.   
  32.       if (env.IsDevelopment())  
  33.       {  
  34.         app.UseDeveloperExceptionPage();  
  35.       }  
  36.       else  
  37.       {  
  38.         app.UseExceptionHandler();  
  39.       }  
  40.   
  41.       app.UseStatusCodePages();  
  42.   
  43.       app.UseMvc();  
  44.   
  45.       //app.Run(async (context) =>  
  46.       //{  
  47.       //  throw new Exception("Test Dev Exception Page");  
  48.       //});  
  49.   
  50.       //app.Run(async (context) =>  
  51.       //{  
  52.       //  await context.Response.WriteAsync("Hello World!");  
  53.       //});  
  54.     }  
  55.   }  
  56. }  

Conclusion

In this article, we learned about serializer settings and most importantly the formatters and how we can enable the API to support content negotiation as well. In the next article of learning ASP.NET Core API we’ll do some more practical stuff when we perform CRUD operations.

Source Code on Github

References

  • https://www.asp.net/core
  • https://www.pluralsight.com/courses/asp-dotnet-core-api-building-first