我在 IIS 中托管一个经典 .NET WebAPI 端点,它接受上传文档的 POST 请求。
我创建了两个控制台应用程序,用于连接到 WebAPI 并上传文档:一个是经典的 .NET (v4.6.2) 控制台应用程序,另一个是 .NET Core 控制台应用程序。代码是完全相同的,但服务对每个的响应不同。 WebAPI 似乎无法读取 .NET Core POST 请求的请求正文,但可以使用经典 .NET POST 请求来读取请求正文。
我有什么遗漏的吗?
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 时,会输出以下内容:
来自经典 .NET 控制台应用程序的 POST 请求:
文档文本:文档文本
来自 .NET Core 控制台应用程序的 POST 请求:
发布的文档为空。
我无法解释行为上的差异。
一些额外的信息:
.NET Core 控制台应用程序的project.json 文件:
{
"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 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 帖子:
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:
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”可能与我的问题有关。但我不明白他们如何/为什么应该在那里。
更新:一些观察
我还创建了一个非常基本的 .NET Core WebAPI 端点,其本质上与上面描述的经典 .NET 执行相同的操作。事实证明,这能够接受来自两个控制台应用程序的 POST 请求。
我还为 .NET Core 创建了第三个控制台应用程序,其中我跳过使用 PostAsJsonAsync,而是将 PostAsync 与 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 和 Classic .NET WebAPI 接受。
Summary
在服务器端我有两个 WebAPI
- /library - 经典.NET
- /library2 - .NET Core
在客户端,我有同一控制台应用程序的三个变体:
- ConsoleApplication1 - Classic .NET using PostAsJsonAsync
- ConsoleApp1 - .NET Core using PostAsJsonAsync
- 使用 /library(经典 .NET)失败,使用 /library2(.NET Core)运行良好
- ConsoleApp2 - .NET Core using PostAsync
这里明显的解决方法是never在 .NET Core 客户端应用程序中使用 PostAsJsonAsync,这很遗憾,因为它确实很方便。 :(
-S