关于json:为什么POST和PUT ReadAsAsync()为空,但ReadAsStringAsync()被填充?又称为”如何关闭分块?”

Why are POSTs and PUTs ReadAsAsync() null, but ReadAsStringAsync() filled? AKA “How do I turn Chunking Off?”

我有一个Web API项目,该项目具有数十种RESTful方法,在GET,POST和PUT之间平均分配。系统使用Entity Framework对象和来自Nuget(版本9.0.1)的Newtonsoft的JSON。

我最近所做的事情突然破坏了所有POST和PUT。我发现我正在POST / PUTTING的[FromBody]对象作为null到达。

所以我的" Update User "方法看起来像这样...

1
2
    [HttpPut]
    public IHttpActionResult Put([FromBody] User user)

...但是" user "始终为null。同样,如果我这样做...

1
  var obj = Request.Content.ReadAsAsync<object>().Result;

...然后obj为空。

但是如果我这样做...

1
var jsonString = Request.Content.ReadAsStringAsync().Result;

...然后我得到了预期的JSON。 (但是对于我的体系结构,我不需要JSON,我想要对象。)

据我了解,如果某人已经阅读了Request.Content,这就是我期望的那种行为。内容流是不可倒带的,并被设置为最后一个字节;但是.ReadAsStringAsync()和.ReadAsByteArrayAsync()通过(我认为)复制流并自己处理流来解决此问题。

我使用HttpClient从WPF应用程序中调用它。样品通话...

1
2
3
4
5
6
7
8
9
10
11
12
using (HttpClient http = API.GetHttpClient())
{
  string url = string.Format("{0}/User", thisApp.WebAPI_BaseUrl);
  RILogManager.Default.SendString("url", url);

  JsonMediaTypeFormatter formatter = new JsonMediaTypeFormatter() ;
  formatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

  HttpResponseMessage response;

  response = http.PutAsync<User>(url, user, formatter,"application/json").Result;
  ...

我的" API.GetHttpClient()"例程如下所示。您可以看到我正在使用DelegateHandler在客户端进行一些JWT工作,但是我认为这与这里无关。它不会触摸传出的请求,而只会触摸传入的响应。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 public static HttpClient GetHttpClient(bool WithAuthToken = true)
 {
     App thisApp = (App)System.Windows.Application.Current;

     //HttpClient http = new HttpClient();
     HttpClient http = HttpClientFactory.Create(new JWTExpirationHandler());

     http.BaseAddress = new Uri(thisApp.WebAPI_BaseUrl);
     http.DefaultRequestHeaders.Accept.Clear();
     http.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

     if(WithAuthToken)
         http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", JWT);

     return http;

 }

我已经确认传入的请求是" application / json "和UTF-8的Content-type。

我在Web服务器上有两个DelegatingHandlers,但这似乎不是问题,因为当我在第一个的顶部执行ReadAsAsync()时,它也为null。而ReadAsStringAsync()返回JSON。

那...我在做什么错?再次,这很好用,并且发生了一些变化,我所有的POST和PUT都以这种方式损坏。

我看到一些链接说要从我的类中删除[Serializable],但是这些是我在很多地方使用的Entity Framework类,我不想这样做。

最后...当我通过Postman调用此Update PUT时,它可以工作。

更新
比较我自己的客户端和Postman的HttpRequest,我发现前者是"块",而后者不是。这似乎是一个重要的线索。我看到其他一些人正在处理相同的问题:

ASP.NET Web Api-使用分块传输编码时,框架未将JSON转换为对象。

我找不到如何关闭分块的任何明确指示。我确实看到有一个属性可以关闭分块,但是这样做没有帮助。

问题:是什么导致"选择"块化?是客户选择执行此操作,还是选择Controller,还是两者之间进行某些协商?


那是一个漫长的过程。

不知道它是如何到达那里的,但是在我的.csproj中,我有以下内容:

1
2
3
4
5
<Reference Include="System.Net.Http, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
  <HintPath>..\\packages\\System.Net.Http.4.3.0\\lib\
et46\\System.Net.Http.dll</HintPath>
  <Private>True</Private>
</Reference>

而不是:

1
<Reference Include="System.Net.Http" />

在我的App.config中,我有以下内容:

1
2
3
4
5
6
7
8
  <dependentAssembly>
   
    <bindingRedirect oldVersion="0.0.0.0-4.1.1.0" newVersion="4.1.1.0" />
  </dependentAssembly>
  <dependentAssembly>
   
    <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
  </dependentAssembly>

...而不是...不是这个。我不需要这个东西。我刚拿出来。