使用 HttpClient PostAsJsonAsync 在 ASP.NET Core 中发送 HTTP POST 消息

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

我想发送像这样的动态对象

new { x = 1, y = 2 };

作为 HTTP POST 消息的正文。所以我试着写

var client = new HttpClient();

但是我找不到方法

client.PostAsJsonAsync()

所以我尝试将 Microsoft.AspNetCore.Http.Extensions 包添加到 project.json 并添加

using Microsoft.AspNetCore.Http.Extensions; 

使用子句。但是它对我没有帮助。

那么在 ASP.NET 核心中发送带有 JSON 主体的 POST 请求的最简单方法是什么?

您应该添加对 "Microsoft.AspNet.WebApi.Client" 包的引用(阅读 this article 获取样本)。

无需任何附加扩展,您可以使用标准 PostAsync 方法:

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

其中 jsonInString 您可以通过调用 JsonConvert.SerializeObject(<your object>);

获得的值

我会在接受的答案中添加您还想将 Accept header 添加到 httpClient:

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

我用这个class:

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

用法示例:

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

你是对的,这早就在 .NET Core 中实现了。

在撰写本文时(2019 年 9 月),NuGet 3.x+ 的 project.json 文件已被 PackageReference 取代(如 https://docs.microsoft.com/en-us/nuget/archive/project-json 所述)。

要访问 HttpClient class 的 *Async 方法,您的 .csproj 文件必须正确配置。

在纯文本编辑器中打开 .csproj 文件,确保第一行是
<Project Sdk="Microsoft.NET.Sdk.Web">
(正如 https://docs.microsoft.com/en-us/dotnet/core/tools/project-json-to-csproj#the-csproj-format 指出的那样)。

要访问 HttpClient class 的 *Async 方法,您还需要在您的 包参考 .csproj 文件,像这样:

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

(参见 https://docs.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files#adding-a-packagereference。 另外:我们建议应用程序以 ASP.NET Core 2.1 为目标,之后使用 Microsoft.AspNetCore.App 元包https://docs.microsoft.com/en-us/aspnet/core/fundamentals/metapackage)

PostAsJsonAsyncReadAsAsyncPutAsJsonAsyncDeleteAsync 等方法现在应该开箱即用。 (不需要使用指令。)

更新: .NET Core 3.0 不再需要 PackageReference 标签。

Microsoft 现在建议使用 IHttpClientFactory 具有以下优势:

  • 为命名和配置逻辑提供了一个中心位置 HttpClient 个实例。例如,名为 github 的客户端可以是 已注册并配置为访问 GitHub。默认客户端可以是 已注册一般访问权。
  • 通过委托处理程序整理传出中间件的概念 在 HttpClient。为 Polly-based 中间件提供扩展 在 HttpClient.
  • 中委派处理程序的优势
  • 管理基础资产池和生命周期 HttpClientMessageHandler 个实例。自动管理避免 手动操作时出现的常见 DNS(域名系统)问题 管理 HttpClient 生命周期。
  • 为所有请求添加可配置的日志记录体验(通过 ILogger) 通过工厂创建的客户端发送。

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

设置:

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 例子:

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

如果您使用的是 .NET 5 或更高版本,您可以(并且应该)使用 System.Net.Http.Json 中的 PostAsJsonAsync 扩展方法:

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

如果您使用的是旧版本的.NET Core,您可以自行实现扩展功能:

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);
    }
}