ChatGPT解决这个技术问题 Extra ChatGPT

Send HTTP POST message in ASP.NET Core using HttpClient PostAsJsonAsync

I want to send dynamic object like

new { x = 1, y = 2 };

as body of HTTP POST message. So I try to write

var client = new HttpClient();

but I can't find method

client.PostAsJsonAsync()

So I tried to add Microsoft.AspNetCore.Http.Extensions package to project.json and add

using Microsoft.AspNetCore.Http.Extensions; 

to uses clause. However It didn't help me.

So what is the easiest way to send POST request with JSON body in ASP.NET Core?

Wonder why this article does not contain an example for POST docs.microsoft.com/en-us/dotnet/csharp/tutorials/…

C
Cobus Kruger

You should add reference to "Microsoft.AspNet.WebApi.Client" package (read this article for samples).

Without any additional extension, you may use standard PostAsync method:

client.PostAsync(uri, new StringContent(jsonInString, Encoding.UTF8, "application/json"));

where jsonInString value you can get by calling JsonConvert.SerializeObject(<your object>);


But Microsoft.AspNet.WebApi.Client doesn't look like ASP.NET Core RC2 library. And the secon way is really too much of code repetition((
@Rem why don't you create an HttpClient extension method(PostAsJsonAsync) to use the second way. It enables you to avoid code repetition.
Sure. But I asked the question in order find out am I missing something. I can't believe it hasn't been implemented in Core yet!
This library isn't a core/.net-standard one, I don't think System.Net.Http.Formatting has been ported yet
This will work for HttpClient created by IHttpClientFactory in .NET Core 2.2 from the nuget package Microsoft.Extensions.Http. However, how do you do it this way but add headers such as an authorization key.
I
IvanH

I use this class:

public class JsonContent : StringContent
{
    public JsonContent(object obj) :
        base(JsonConvert.SerializeObject(obj), Encoding.UTF8, "application/json")
    { }
}

Sample of usage:

new HttpClient().PostAsync("http://...", new JsonContent(new { x = 1, y = 2 }));

Why not an extension method? public static class JsonContent { public Task PostAsJSonAsync(this HttpClient client, object toSerializeAsJson) { ... } }
I like the JsonContent class approach
Does this set Content-Length: HTTP header?
@VyacheslavNapadovsky it depends on HttpClient settings, e.g. if one set client.DefaultRequestHeaders.TransferEncodingChunked = true Content-Length header wouldn't be set and Transfer-Encoding: chunked would be set instead. However, if one creates the client like var client = new HttpClient();, the header Content-Length would be set for this content class by default.
S
Serj Sagan

I would add to the accepted answer that you would also want to add the Accept header to the httpClient:

httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

O
Ogglas

Microsoft now recommends using an IHttpClientFactory with the following benefits:

Provides a central location for naming and configuring logical HttpClient instances. For example, a client named github could be registered and configured to access GitHub. A default client can be registered for general access.

Codifies the concept of outgoing middleware via delegating handlers in HttpClient. Provides extensions for Polly-based middleware to take advantage of delegating handlers in HttpClient.

Manages the pooling and lifetime of underlying HttpClientMessageHandler instances. Automatic management avoids common DNS (Domain Name System) problems that occur when manually managing HttpClient lifetimes.

Adds a configurable logging experience (via ILogger) for all requests sent through clients created by the factory.

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-3.1

Setup:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHttpClient();
        // Remaining code deleted for brevity.

POST example:

public class BasicUsageModel : PageModel
{
    private readonly IHttpClientFactory _clientFactory;

    public BasicUsageModel(IHttpClientFactory clientFactory)
    {
        _clientFactory = clientFactory;
    }
    
    public async Task CreateItemAsync(TodoItem todoItem)
    {
        var todoItemJson = new StringContent(
            JsonSerializer.Serialize(todoItem, _jsonSerializerOptions),
            Encoding.UTF8,
            "application/json");
            
        var httpClient = _clientFactory.CreateClient();
        
        using var httpResponse =
            await httpClient.PostAsync("/api/TodoItems", todoItemJson);
    
        httpResponse.EnsureSuccessStatusCode();
    }

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-3.1#make-post-put-and-delete-requests


What is the _jsonSerializerOptions part? Do you know if any options need to be set?
@Lukas See here: docs.microsoft.com/en-us/dotnet/standard/serialization/… Microsoft has it in their example code but try without and see what happens. :)
M
Mark Lagendijk

If you are using .NET 5 or above, you can (and should) use the PostAsJsonAsync extension method from System.Net.Http.Json:

httpClient.PostAsJsonAsync(url, new { 
    x = 1, 
    y = 2 
});

If you are using an older version of .NET Core, you can implement the extension function yourself:

public static class HttpClientExtensions
{
    public static Task<HttpResponseMessage> PostJsonAsync(this HttpClient httpClient, string url, object body)
    {
        var bodyJson = JsonSerializer.Serialize(body);
        var stringContent = new StringContent(bodyJson, Encoding.UTF8, "application/json");
        return httpClient.PostAsync(url, stringContent);
    }
}

H
Henke

You are right that this has long since been implemented in .NET Core.

At the time of writing (September 2019), the project.json file of NuGet 3.x+ has been superseded by PackageReference (as explained at https://docs.microsoft.com/en-us/nuget/archive/project-json).

To get access to the *Async methods of the HttpClient class, your .csproj file must be correctly configured.

Open your .csproj file in a plain text editor, and make sure the first line is
<Project Sdk="Microsoft.NET.Sdk.Web">
(as pointed out at https://docs.microsoft.com/en-us/dotnet/core/tools/project-json-to-csproj#the-csproj-format).

To get access to the *Async methods of the HttpClient class, you also need to have the correct package reference in your .csproj file, like so:

<ItemGroup>
    <!-- ... -->
    <PackageReference Include="Microsoft.AspNetCore.App" />
    <!-- ... -->
</ItemGroup>

(See https://docs.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files#adding-a-packagereference. Also: We recommend applications targeting ASP.NET Core 2.1 and later use the Microsoft.AspNetCore.App metapackage, https://docs.microsoft.com/en-us/aspnet/core/fundamentals/metapackage)

Methods such as PostAsJsonAsync, ReadAsAsync, PutAsJsonAsync and DeleteAsync should now work out of the box. (No using directive needed.)

Update: The PackageReference tag is no longer needed in .NET Core 3.0.


I couldn't manage to get PostAsJsonAsync to work with .NET Core 3.1. Thanks