Home > .NET Core, C# > JSON handling made easy with System.Net.Http.Json

JSON handling made easy with System.Net.Http.Json

Nowadays, we all have to deal with JSON, the de facto standard for data interchange in HTTP communications. In the rest of the article, we’ll use JSONPlaceholder, a fake Online REST API Server. Suppose we have the following class and initialization for HttpClient and JsonSerializer:

public class Post
{
    public int Id { get; set; }

    public int UserId { get; set; }

    public string Title { get; set; }

    public string Body { get; set; }
}

private static readonly HttpClient httpClient = new HttpClient
  {
      BaseAddress = new Uri("https://jsonplaceholder.typicode.com")
  };

private static readonly JsonSerializerOptions jsonSerializerOptions
    = new JsonSerializerOptions
    {
        PropertyNameCaseInsensitive = true,
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase
    };

If we want to get all the posts, we usually write something like this:

private static async Task<IEnumerable<Post>> GetPostsAsync()
{
    using var response = await httpClient.GetAsync("posts");
    response.EnsureSuccessStatusCode();

    using var contentStream = await response.Content.ReadAsStreamAsync();
    
    var posts = await JsonSerializer.DeserializeAsync<IEnumerable<Post>>
        (contentStream, jsonSerializerOptions);

    return posts;
}

Of course, there are different ways (more or less efficient) to get the results, but, in general, we always make the request, read its content and deserialize it. Note that, for the sake of simplicity, we don’t have any error handling.

In the same way, in order to make a POST we need the following:

private static async Task SendPostAsync(Post post)
{
    var jsonContent = JsonSerializer.Serialize(post, jsonSerializerOptions);
    using var httpContent = new StringContent
        (jsonContent, Encoding.UTF8, "application/json");

    using var response = await httpClient.PostAsync("posts", httpContent);
    
    response.EnsureSuccessStatusCode();
}

We serialize the input object, create the HttpContent using the correct encoding and media type and then make the POST request to the server.

Even if this is not too complex, it is the classic example of boilerplate code. But now we have an official alternative: during the Build 2020 event, the new System.Net.Http.Json package has been released as stable version. It provides some extension methods for HttpClient that make working with JSON very straightforward. For example, after adding this package to our project, we can update the previous code in this way:

private static async Task<IEnumerable<Post>> GetPostsAsync()
{
    var posts = await httpClient.GetFromJsonAsync<IEnumerable<Post>>("posts");

    return posts;
}

private static async Task SendPostAsync(Post post)
{
    using var response = await httpClient.PostAsJsonAsync("posts", post);

    response.EnsureSuccessStatusCode();
}

As we can see, every operation is reduced to a single line of code. Under the hood, it uses JsonSerializer for serialization/deserialization, so for example (besides the classic HttpClient exceptions) we obtain a JsonException if the JSON is invalid. Moreover, if the content type is incorrect for JSON requests, we get a NotSupportedException. And we don’t need to pass anymore a JsonSerializerOptions object to these methods, because they automatically use one with Camel case naming policy and case-insensitive comparison during deserialization (as we normally expect when working with JSON).

If we want more control while sending and receiving, we can leverage some other extension methods and helpers:

private static async Task<IEnumerable<Post>> GetPostsAsync()
{
    using var request = new HttpRequestMessage(HttpMethod.Get, "posts");

    // Additional code for HttpRequest...

    using var response = await httpClient.SendAsync(request);
    response.EnsureSuccessStatusCode();

    var posts = await response.Content.ReadFromJsonAsync<IEnumerable<Post>>();

    return posts;
}

private static async Task SendPostAsync(Post post)
{
    using var request = new HttpRequestMessage(HttpMethod.Post, "posts")
    {
        Content = JsonContent.Create(post)
    };

    // Additional code for HttpRequest...

    using var response = await httpClient.SendAsync(request);

    response.EnsureSuccessStatusCode();
}

At line 10 we have used the ReadFromJsonAsync extension method on the HttpContent class, while at line 19 we have created the content for the HttpRequestMessage with the JsonContent helper.

This new approach should become the “standard”, because, among the other things, it internally uses Span<T> for serialization/deserialization, so it can be more efficient than the “classic” code we have used till today.

Categories: .NET Core, C#
  1. No comments yet.
  1. 22/05/2020 at 13:19

Leave a comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: