Has HttpContent.ReadAsAsync<T> method been superceded in .NET Core?
Asked Answered
A

5

11

The following refers to a .NET Core application with dependencies as follows...

Microsoft.NETCore.App
Microsoft.AspNet.WepApi.Client (5.2.7)

At Microsoft.com is the document Call a Web API From a .NET Client (C#) from 2017 November.

Link... https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/calling-a-web-api-from-a-net-client

Within the document is this client side invocation of HTTP GET.

    static HttpClient client = new HttpClient();
    static async Task<Product> GetProductAsync(string path)
    {
        Product product = null;
        HttpResponseMessage response = await client.GetAsync(path);
        if (response.IsSuccessStatusCode)
        {
            product = await response.Content.ReadAsAsync<Product>();
        }
        return product;
    }

The value response.Content refers to an HttpContent object. As of 2020 July HttpContent has no instance method with the signature ReadAsAsync<T>(), at least according to the following document. However, this instance method works.

Reference link to where there is no instance method with the signature ReadAsAsync<T>()... https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpcontent?view=netcore-3.1

There is a static method HttpContentExtensions.ReadAsAsync<T>(myContent) where myContent refers to an HttpContent object. This static method also works.

Reference link... https://learn.microsoft.com/en-us/previous-versions/aspnet/hh834253(v=vs.118)

For example one documented signature has the...

static icon followed by ReadAsAsync<T>(HttpContent)

and a description that says it will return Task<T>. This static method is probably the behind the scenes implementation of the instance method.

However there is information at the top of the static method webpage that indicates... "We're no longer updating this content regularly. Check the Microsoft Product Lifecycle for information about how this product, service, technology, or API is supported."

Has HttpContent.ReadAsAsync<T>() of both forms, instance and static, been superceded in .NET Core 3.1?

Alloplasm answered 27/7, 2020 at 3:27 Comment(3)
Though the documentation is confusing and does not reassure that the 2017 November is supposed to work, I decided to accept it as being a "good enough" example for a .NET Core project.Alloplasm
This link could be of interest from 2020 July 28. visualstudiomagazine.com/articles/2020/07/28/… Quoting from it... "Note that NuGet doesn't tell the whole story, however, as the System.Text.Json library is included in the .NET Core 3.0 shared framework, while for other target frameworks, developers need to install the System.Text.Json NuGet package."Alloplasm
As of today there still is no replacement in .Net Core 3.1 for ReadAsAsync<T>.... You have to create your own... or keep using the ApiClient version 5.2.7 which clearly has a dependency on Newtonsoft JSONAbert
S
3

I can't tell from the code if it ever was an instance method but it probably was.

The links you included alternate between .net 4.x and .net core, it's not clear if you are aware of this. Labelling them with dates suggests a linear progression but we have a fork in the road.

And that is all, it was 'demoted' to residing in an additional package because it will be used less. In .net core we now have similar extensionmethods acting on HttpClient directly.


In order to use this with .net core 3.x you may have to add the System.Net.Http.Json nuget package. The extensions only work with System.Text.Json, for Newtonsoft you will have to use the traditional code patterns.

Sideward answered 27/7, 2020 at 4:36 Comment(11)
That's good to know. However, in HttpClientExtensions I do not see a GET method. They are all POST and PUT. learn.microsoft.com/en-us/previous-versions/aspnet/…Alloplasm
You have to be clear about wanting 4.x or core. There also is an entanglement with NewtonSoft vs System.Text.Json .Sideward
In .net core we have HttpClientJsonExtensions and GetFromJsonAsync<>()Sideward
I want Core. Unfortunately not all documentation pages have a drop-down list to select only Core documentation. I will look into HttpClientJsonExtensions, thanks.Alloplasm
HttpClientJsonExtensions appears to be absent from .NET Core as of 2020 July.Alloplasm
'2020 july' is not a meaningful version indicator. Here is the latest (net 5) version with a dropdown.Sideward
But it seems 3.1 is not documented, I will have to look.Sideward
Simply false.... I just created a project and it works without the nugets you mention.....Abert
This is just a note for people that read this in the future. In 2020 July the current version of .NET Core is 3.1. In the future it is believed that the brand "Core" will be dropped when the successor is named .NET 5. Anyway, these are just identifiers and so they're not as important as the matter that to write cross platform today, you are supposed to select Core libraries and make VS target "Core" unless you want the preliminary .NET 5 preview. Since I don't like previews, the brand "Core" still matters for me. May be I should have mentioned it earlier.Alloplasm
At this link... visualstudiomagazine.com/articles/2020/07/28/… It seems to say that .NET Core 3.0 users do not need to add System.Text.Json because it is already included.Alloplasm
When you say "acting on HttpClient directly" do you mean .GetByteArrayAsync(), .GetStreamAsync(), .GetStringAsync(). These are not comparable to HttpContent.ReadAsAsync<T>() because they are not type safe and very inconvenient if the payload is an object tree. If you have an HttpClient method that is type safe, please let me know.Alloplasm
A
9

The other answers are not correct.

The method ReadAsAsync is part of the System.Net.Http.Formatting.dll

Which in turn is part of the nuget: Microsoft.AspNet.WebApi.Client

I just created a new Console project .Net Core 3.1 and added 2 nugets

  1. Newtonsoft
  2. Microsoft.AspNet.WebApi.Client

I created a project with .NET Core 3.1 here are some pictures: enter image description here

Here is my project file: enter image description here

Here is the code I just wrote which compiles just fine:

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace Custom.ApiClient
{
    internal static class WebApiManager
    {
        //private const string _requestHeaderBearer = "Bearer";
        private const string _responseFormat = "application/json";

        private static readonly HttpClient _client;

        static WebApiManager()
        {

            // Setup the client.
            _client = new HttpClient { BaseAddress = new Uri("api url goes here"), Timeout = new TimeSpan(0, 0, 0, 0, -1) };

            _client.DefaultRequestHeaders.Accept.Clear();
            _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(_responseFormat));

            // Add the API Bearer token identifier for this application.
            //_client.DefaultRequestHeaders.Add(RequestHeaderBearer, ConfigHelper.ApiBearerToken);       
        }

        public static async Task<T> Get<T>()
        {
            var response = _client.GetAsync("api extra path and query params go here");

            return await ProcessResponse<T>(response);
        }

        private static async Task<T> ProcessResponse<T>(Task<HttpResponseMessage> responseTask)
        {
            var httpResponse = await responseTask;

            if(!httpResponse.IsSuccessStatusCode)
                throw new HttpRequestException(httpResponse.ToString());

            var dataResult = await httpResponse.Content.ReadAsAsync<T>();

            return dataResult;
        }
    
    }
}

UPDATE:

To clear some confusion about the dependecies for package Microsoft.AspNet.WebApi.Client

Here is a picture of the dependecies showing as of 2020-10-27 the dependencies which clearly shows it depends on Newtonsoft JSON 10 or higher. As of today there is no replacement of ReadAsAsync using System.Text.Json... So you can use ApiClient + Newtonsoft Json or create your own using System.Text.Json

enter image description here

Abert answered 27/7, 2020 at 6:32 Comment(7)
OK, this works with NewtonSoft. You may need that for some backward compatibility but System.Text.Json is the way forward, and some 20% faster in general.Sideward
@HenkHolterman if you see the picture the Microsoft.AspNet.WebApi.Client depends on Newtonsoft and it is the package the he has installed according to the question. As for being "faster" it is for some scenarios... but for a lot of things System.Text.Json is pretty unfinished... I would not use it in production. It still has a lot of rough edges. And by far the most stable json serializer for .net is Newtonsoft which has more than 500 million downloads.Abert
Your code relies on the same objects as mine. Your code uses HttpClient.GetAsync() and HttpConent.ReadAsAsync<T>(). My code works without Newtonsoft so it is very likely your code does not need Newtonsoft.Alloplasm
@Alloplasm You are wrong on this one. Package Microsoft.AspNet.WebApi.Client does depende on Newtonsoft JSON..... Just look at the dependency list..... ReadAsAsync<T> depdends on Newtonsoft JSON and as of today there is no replacement for this using System.Text.Json... you would have to create your own.Abert
@Alloplasm furthermore when you install package Microsoft.AspNet.WebApi.Client 5.2.7 it automatically installs Newtonsoft JSON version 10 as a depdency... I recommend you upgrade Newtonsoft JSON manually to the latest versionAbert
Good information. Thank you. It's convenient that Microsoft has the dependency on Newtonsoft hidden and automatic. It is one less thing to install. Under Packages, under Microsoft.AspNet.WebApi.Client (5.2.7), there is the item Newtonsoft.Json (10.0.1).Alloplasm
Wanted to use Microsoft.AspNet.WebApi.Client for this purpose only in a class library, but refrained since it dragged 50+ depencies with it. The solution with an Extension-method was more appealing.Photoengrave
S
7

If you don't want to install third party nuget packages, it's not too difficult to implement an extension method for this.

For example, using System.Text.Json:

using System.IO;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;

public static class HttpContentExtensions {

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

    public static async Task<T> ReadAsAsync<T>(this HttpContent content, JsonSerializerOptions options = null) {
        using(Stream contentStream = await content.ReadAsStreamAsync()) {
            return await JsonSerializer.DeserializeAsync<T>(contentStream, options ?? defaultOptions);
        }
    }

}
Surfeit answered 1/6, 2021 at 5:23 Comment(0)
B
4

The most direct equivalent, as of .NET 5:

response.content.ReadFromJsonAsync<T>()

JsonSerializerOptions can also be supplied as a optional argument.

See: HttpContentJsonExtensions.ReadFromJsonAsync Method

Bunder answered 1/8, 2023 at 22:38 Comment(1)
Thank you for contributing to the Stack Overflow community. This may be a correct answer, but it’d be really useful to provide additional explanation of your code so developers can understand your reasoning. This is especially useful for new developers who aren’t as familiar with the syntax or struggling to understand the concepts. Would you kindly edit your answer to include additional details for the benefit of the community?Barolet
S
3

I can't tell from the code if it ever was an instance method but it probably was.

The links you included alternate between .net 4.x and .net core, it's not clear if you are aware of this. Labelling them with dates suggests a linear progression but we have a fork in the road.

And that is all, it was 'demoted' to residing in an additional package because it will be used less. In .net core we now have similar extensionmethods acting on HttpClient directly.


In order to use this with .net core 3.x you may have to add the System.Net.Http.Json nuget package. The extensions only work with System.Text.Json, for Newtonsoft you will have to use the traditional code patterns.

Sideward answered 27/7, 2020 at 4:36 Comment(11)
That's good to know. However, in HttpClientExtensions I do not see a GET method. They are all POST and PUT. learn.microsoft.com/en-us/previous-versions/aspnet/…Alloplasm
You have to be clear about wanting 4.x or core. There also is an entanglement with NewtonSoft vs System.Text.Json .Sideward
In .net core we have HttpClientJsonExtensions and GetFromJsonAsync<>()Sideward
I want Core. Unfortunately not all documentation pages have a drop-down list to select only Core documentation. I will look into HttpClientJsonExtensions, thanks.Alloplasm
HttpClientJsonExtensions appears to be absent from .NET Core as of 2020 July.Alloplasm
'2020 july' is not a meaningful version indicator. Here is the latest (net 5) version with a dropdown.Sideward
But it seems 3.1 is not documented, I will have to look.Sideward
Simply false.... I just created a project and it works without the nugets you mention.....Abert
This is just a note for people that read this in the future. In 2020 July the current version of .NET Core is 3.1. In the future it is believed that the brand "Core" will be dropped when the successor is named .NET 5. Anyway, these are just identifiers and so they're not as important as the matter that to write cross platform today, you are supposed to select Core libraries and make VS target "Core" unless you want the preliminary .NET 5 preview. Since I don't like previews, the brand "Core" still matters for me. May be I should have mentioned it earlier.Alloplasm
At this link... visualstudiomagazine.com/articles/2020/07/28/… It seems to say that .NET Core 3.0 users do not need to add System.Text.Json because it is already included.Alloplasm
When you say "acting on HttpClient directly" do you mean .GetByteArrayAsync(), .GetStreamAsync(), .GetStringAsync(). These are not comparable to HttpContent.ReadAsAsync<T>() because they are not type safe and very inconvenient if the payload is an object tree. If you have an HttpClient method that is type safe, please let me know.Alloplasm
R
1

Something I used recently, I had to install Newtonsoft.Json

string responseContent = await response.Content.ReadAsStringAsync();
var productResult = JsonConverter.DeserializeObject<Product>(responseContent);

I actually found this in Microsoft documents on how to consume a REST API, and it worked. Your code is ok on the get part, assuming it has the right Uri,

Also something to not is my code wasn't static

Ranking answered 27/7, 2020 at 3:28 Comment(6)
just 2 cents to anyone reading this answer. This works but consider that it allocates a string which is an unnecessary step.Wycoff
product = JsonConverter.DeserialzeObject<Product>(await response.Content.ReadAsStringAsync());Ranking
still allocating a stringWycoff
Read as string will read the content to a string, then you are deserializing that string to an object. There is support for reading the stream directly to an object so the intermediary step of reading into a string first is not neededWycoff
You can read about it here for newtonsoft's support: newtonsoft.com/json/help/html/Performance.htmWycoff
Why use strings if there is no intention to do "string operations" like concatenate, substring, trim, etc?Alloplasm

© 2022 - 2024 — McMap. All rights reserved.