I have existing third party DLL – which has several classes. I don’t have source code of this DLL.
Lets assume that it has Book class defined as below
public class Book{
public String Id { get; set; }
public String Title { get; set; }
public String Author{ get; set; }
public List<Page> Pages { get; set; }
}
I have created Asp.net Core Web API project and referred DLL and wrote API Controller for GET method of http.
[HttpGet("{id}")]
public ActionResult<Book> Get(string id)
{
Book b = Book.FindById(id); // This utility function returns Book instance.
return Ok(b);
}
My requirement is return value of JSON should be something like
{
"id" : "1234",
"Title" : "How to Custom Serialize JSON",
"Author" : "Myself",
"NumberOfPages" : 100
}
So basically, whenever JSON serialization happens, I want to ensure that Pages attribute is not serialized as it has many complications. But I should able to add new attribute NumberOfPages. Basically I want to take control of Serialization. I have seen many examples but I could not find this particular case where I want to custom serialize existing class.
I am not worrying about Deserialization right now.
I can see that Serialization starts from
Microsoft.AspNetCore.Mvc.Formatters.JsonOutputFormatter.WriteObject(TextWriter writer, Object value)
Thanks,
Atul
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
In order to have a solution which works globally:
- Create a custom converter
- Register that converter
Create Converter
The simplest approach: create a class which derives from JsonConverter:
public class BookConverter : JsonConverter<Book>
{
public override void WriteJson(JsonWriter writer, Book value, JsonSerializer serializer)
{
var bookObject = (JObject)JToken.FromObject(value);
bookObject.Remove(nameof(value.Pages));
bookObject.Add(new JProperty("NumberOfPages", value.Pages.Count));
bookObject.WriteTo(writer);
}
public override Book ReadJson(JsonReader reader, Type objectType, Book existingValue, bool hasExistingValue, JsonSerializer serializer)
{
return new Book(); //TODO: fix me, now it is enough to make it compile
}
}
- Here I have converted the
Bookinstance (value) to aJObject. - I have ignored the
Pagesproperty by calling theRemove. - I have extended the output with
NumberOfPagesby calling theAdd. - I’ve skipped the
ReadJsonpart, because it is out of scope for this question.
Register Converter
.NET Core 2.x
public void ConfigureServices(IServiceCollection services)
{
services
.AddControllers()
.AddJsonOptions(opts =>
{
opts.SerializerSettings.Converters.Add(new BookConverter());
});
}
.NET Core 3.x or .NET 5.x
In case of ASP.NET Core 3.1 or above the default json serializer is the System.Text.Json. In order to use Json.Net you need to install the Microsoft.AspNetCore.Mvc.NewtonsoftJson package. This exposes a method called AddNewtonsoftJson where you can register the custom converter:
public void ConfigureServices(IServiceCollection services)
{
services
.AddControllers()
.AddNewtonsoftJson(opts =>
{
opts.SerializerSettings.Converters.Add(new BookConverter());
});
}
With this approach all Book instances will be converted into the desired format when ASP.NET Core calling the serializer.
Method 2
I would take a different appoach:
- Create simple Data Transfer Objects (DTOs) for the public API. This way you can add what properties you want and leave out those you want to hide.
- Use Automapper to perform the tedious copying of properties between the 3rd party classes and your DTO objects.
For a better description of the idea than I’m able to write, see for example https://docs.microsoft.com/en-us/aspnet/web-api/overview/data/using-web-api-with-entity-framework/part-5
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0