Asp.net web api HttpWebRequest完成大文件流传输之前的Web API Post hit
在我们的应用程序(Silverlight 5浏览器外客户端访问WebApi服务器)中,我们经常使用HttpClient发布/获取/删除客户端和服务器之间的所有实体。这在大多数情况下都可以正常工作,但最近我们在上传(发布)更大的实体(>30/35mb)时遇到了一个问题:我们启动流处理,在完成之前,我们在Web API上的Post方法被命中,接收到一个空实体 我们无法理解发生了什么,并且怀疑一定有一些与时间相关的问题,因为这一切都取决于上传的大小 为了进一步解释,我们的客户总结如下:Asp.net web api HttpWebRequest完成大文件流传输之前的Web API Post hit,asp.net-web-api,Asp.net Web Api,在我们的应用程序(Silverlight 5浏览器外客户端访问WebApi服务器)中,我们经常使用HttpClient发布/获取/删除客户端和服务器之间的所有实体。这在大多数情况下都可以正常工作,但最近我们在上传(发布)更大的实体(>30/35mb)时遇到了一个问题:我们启动流处理,在完成之前,我们在Web API上的Post方法被命中,接收到一个空实体 我们无法理解发生了什么,并且怀疑一定有一些与时间相关的问题,因为这一切都取决于上传的大小 为了进一步解释,我们的客户总结如下: HttpRes
HttpResponseMessage response = await _client.SendAsync(request);
string jsonResult = await response.Content.ReadAsStringAsync();
。。。其中uclient是我们的HttpClient,请求我们的HttpRequestMessage。如果它也是相关的(我尽量不让问题充斥代码:),那么请求中的内容如下所示:
request.Content = new StringContent(JsonConvert.SerializeObject(content), Encoding.UTF8, "application/json");
好的,当我们调试这个方法时,服务器上的Post方法在Wait_client.SendAsync(请求)完成之前被命中,这在某种程度上“解释”了为什么它在这种情况下(较大的实体)接收空实体,当它工作时,等待调用完成,然后命中Post
如果由于HttpClient上的某些限制(关于AllowWriteStreamBuffering的访问),if对它有更多的了解,我们还测试了一个等效的场景,但直接使用HttpWebRequest。。。不幸的是,行为完全相同。以下是相关摘录:
httpRequest.BeginGetRequestStream(RequestStreamCallback, httpRequest);
(其中httpRequest是我们的HttpWebRequest,AllowWriteStreamBuffering=false),处理请求流的回调如下所示:
private void RequestStreamCallback(IAsyncResult ar)
{
var request = ar.AsyncState as System.Net.HttpWebRequest;
if (request != null)
{
var requestStream = request.EndGetRequestStream(ar);
var streamWriter = new StreamWriter(requestStream) {AutoFlush = true};
streamWriter.Write(_jsonContent);
streamWriter.Close();
requestStream.Close(); // Belt and suspenders... shouldn't be needed
// Make async call for response
request.BeginGetResponse(ResponseCallback, request);
}
}
同样,对于较大的实体,当我们调试Web API上的Post方法时,会在streamWriter.Write完成并命中streamWriter.Close之前命中(带有空参数)
我们已经读遍了所有的地方,并为此奋斗了好几天。任何帮助都将不胜感激 万一有人碰到这件事,我终于弄明白了到底发生了什么 本质上,Web API Post方法中的模型绑定机制在对JSON进行反序列化时抛出异常,但异常多少有些“隐藏”。。。至少如果您不太了解Web API的内部工作原理,就像我的情况一样 我的Post方法最初缺少此验证检查:
var errors = "";
if (!ModelState.IsValid)
{
foreach (var prop in ModelState.Values)
{
foreach (var modelError in prop.Errors.Where(modelError => modelError != null))
{
if (modelError.Exception != null)
{
errors += "Exception message: " + modelError.Exception.Message + Environment.NewLine;
errors += "Exception strack trace: " + modelError.Exception.StackTrace + Environment.NewLine;
}
else
errors += modelError.ErrorMessage + Environment.NewLine;
errors += " --------------------- " + Environment.NewLine + Environment.NewLine;
}
}
return Request.CreateErrorResponse(HttpStatusCode.NoContent, errors);
}
这是一个“样本”检查,主要目的是验证ModelState的有效性。。。在我们的中断场景中,is无效,因为Web API无法绑定实体,原因可以在ModelState.Values的Errors属性中找到。正如前面提到的,Post被点击是正常的,但是有一个空实体
顺便说一句,问题主要是因为我们没有真正的流式传输内容,而是使用了一个试图完全反序列化的StringContent。。。但这是另一个故事,我们在这里主要关心的是不了解发生了什么以及在哪里
希望这有帮助