HttpClient PostAsJsonAsync 在 .NET Core 和 Classic .NET 中的行为不同 [英] HttpClient PostAsJsonAsync behaving different in .NET Core and Classic .NET

查看:30
本文介绍了HttpClient PostAsJsonAsync 在 .NET Core 和 Classic .NET 中的行为不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 IIS 中托管了一个 Classic .NET WebAPI 端点,它接受 POST 请求来上传文档.

I am hosting a Classic .NET WebAPI endpoint in IIS that accepts POST requests to upload a document.

我创建了两个控制台应用程序,它们将连接到 WebAPI 并上传文档:一个是经典的 .NET (v4.6.2) 控制台应用程序,另一个是 .NET Core 控制台应用程序.代码相同,但服务对每个代码的响应不同.WebAPI 似乎无法读取 .NET Core POST 请求的请求正文,但可以通过经典 .NET POST 请求读取.

I have created two console applications that will connect to the WebAPI and upload a document: One is a classic .NET (v4.6.2) console application, the other is a .NET Core console application. The code is identical, but the service responds differently to each. The WebAPI seems to be unable to read the request body of the .NET Core POST request, but is able to do so with the Classic .NET POST request.

有什么我遗漏的吗?

WebAPI 端点

http://localhost/WebApi/Library/api/Documents

[Route("api/Documents")]
public class DocumentsController : ApiController
{
    [HttpPost()]
    public void Create([FromBody] Document document)
    {
        if (document == null)
        {
            Debug.WriteLine("Posted document is null.");
        }
        else
        {
            Debug.WriteLine($"Document text: {document.Text}");
        }
    }
}

public class Document
{
    public string Text { get; set; }
}

.NET Core/经典 .NET 控制台应用程序

class Program
{
    static void Main(string[] args)
    {
        RunAsAsync().Wait();
    }

    static async Task RunAsAsync()
    {
        var httpClient = new HttpClient()
        {
            BaseAddress = new Uri("http://api-localhost"),
        };

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

        await httpClient.PostAsJsonAsync("/library/api/documents", new Document() { Text = "The document text" });
    }
}

public class Document
{
    public string Text { get; set; }
}

事情是这样的:当我将调试器附加到 WebAPI 时,会输出以下内容:

The thing is this: When I attach the debugger to the WebAPI the following is outputted:

来自经典 .NET 控制台应用程序的 POST 请求:

POST Request from the Classic .NET console application:

文档文本:文档文本

来自 .NET Core 控制台应用程序的 POST 请求:

POST Request from the .NET Core console application:

发布的文档为空.

我无法解释行为的差异.

I am at a loss at explaining the difference in behavior.

一些额外的信息:

.NET Core 控制台应用程序的 project.json 文件:

.NET Core console application's project.json file:

{
  "version": "1.0.0-*",
  "buildOptions": {
    "emitEntryPoint": true
  },

  "dependencies": {
    "Microsoft.AspNet.WebApi.Client": "5.2.3",
    "Microsoft.NETCore.App": {
      "type": "platform",
      "version": "1.0.1"
    },
    "System.Net.Http": "4.3.0",
    "System.Runtime.Serialization.Xml": "4.3.0"

  },

  "frameworks": {
    "netcoreapp1.0": {
      "imports": [
        "dnxcore50",
        "portable-net451+win8"
      ]
    }
  }
}

经典 .NET 包.config:

Classic .NET packages.config:

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Microsoft.AspNet.WebApi.Client" version="5.2.3" targetFramework="net462" />
  <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net462" />
</packages>

来自 Fiddler,原始 .NET Core 帖子:

From Fiddler, the raw .NET Core post:

POST http://localhost/library/api/documents HTTP/1.1
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Accept: application/json
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Host: api-localhost

1c
{"Text":"The document text"}
0

这是原始的经典 .NET POST:

And here's the raw Classic .NET POST:

POST http://localhost/library/api/documents HTTP/1.1 Accept:
application/json Content-Type: application/json; charset=utf-8 Host:
api-localhost Content-Length: 28 Expect: 100-continue Connection:
Keep-Alive

{"Text":"The document text"}

在我看来,奇怪的1c"和0"可能与我的问题有关.但我不明白他们如何/为什么应该在那里.

It seems to me that the weird "1c" and "0" might have something to do with my problem. But I don't see how/why they should even be there.

更新:一些观察

我还创建了一个非常基本的 .NET Core WebAPI 端点,它基本上与上面描述的经典 .NET 执行相同的操作.这证明能够接受来自两个控制台应用程序的 POST 请求.

I also created a very basic .NET Core WebAPI end point that essentially does the same thing as the Classic .NET described up top. This proved to be able to accept the POST request from both console applications.

我还为 .NET Core 创建了第三个控制台应用程序,我跳过使用 PostAsJsonAsync 而是使用带有 StringContent 的 PostAsync:

I also created a third console application for .NET Core where I skip using the PostAsJsonAsync and instead use PostAsync with StringContent:

public class Program
{
    static void Main(string[] args)
    {
        RunAsAsync().Wait();
    }

    static async Task RunAsAsync()
    {
        var httpClient = new HttpClient()
        {
            BaseAddress = new Uri("http://localhost"),
        };

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

        var document = new Document() { Text = "The document text." };

        var content = JsonConvert.SerializeObject(document);

        HttpContent httpContent = new StringContent(content, Encoding.UTF8, "application/json");

        await httpClient.PostAsync("/library2/api/documents", httpContent);
    }
}

public class Document
{
    public string Text { get; set; }
}

在/library/... 和/library2/... 之间交替,来自此应用程序的 POST 请求被 .NET Core 和经典 .NET WebAPI 接受.

Alternating between /library/... and /library2/..., the POST request from this application is accepted by both the .NET Core and the Classic .NET WebAPIs.

总结

在服务器端我有两个 WebAPI

On the server side I have two WebAPIs

  • /library - 经典 .NET
  • /library2 - .NET 核心

在客户端,我有同一个控制台应用程序的三个变体:

On the client side I have three variants of the same console applicaton:

  • ConsoleApplication1 - 使用 PostAsJsonAsync 的经典 .NET
    • 适用于两个 WebAPI
    • 使用/library(经典 .NET)失败,适用于/library2(.NET Core)
    • 适用于两个 WebAPI

    这里明显的变通方法是永远在 .NET Core 客户端应用程序中使用 PostAsJsonAsync,这是一种耻辱,因为它真的很方便.:(

    The obvious work-around here is to never use PostAsJsonAsync in a .NET Core client applicaton, which is a shame since it is really convenient. :(

    -S

    推荐答案

    潜在问题似乎是 Classic .NET WebAPI 无法处理当前最新版本 (v5.2.3) 中的分块请求.我将假设这是一个错误,并作为暂时降级到 v5.0 的解决方法.

    The underlying problem appears to be that the Classic .NET WebAPI fails to process chunked requests in it current newest version (v5.2.3). I'm going to assume that's a bug and as a work-around downgrade to v5.0 for the time being.

    特别感谢@Developer 提供有用的输入.

    Special thanks to @Developer for helpful input.

    -S

    这篇关于HttpClient PostAsJsonAsync 在 .NET Core 和 Classic .NET 中的行为不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆