网页API后打之前的HttpWebRequest已完成流大文件 [英] Web API Post hit before HttpWebRequest has finished streaming a large file

查看:231
本文介绍了网页API后打之前的HttpWebRequest已完成流大文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我们的应用程序(Silverlight的5外的浏览器客户端击中的WebAPI服务器)我们经常使用的HttpClient张贴/获取/删除等我们的客户端和服务器之间的所有实体。这一切工作正常的大部分时间,但最近我们已经上传(发帖)更大的实体(> 30 / 35MB)时遇到的一个问题:我们开始流过程,之前,它是完成了我们的Post方法上的Web API被击中,接收空实体。

In our app (Silverlight 5 out-of-browser client hitting a WebApi server) we routinely use an HttpClient for posting/getting/deleting and so on all our entities between client and server. This all works fine most of the time, but recently we have run into an issue when uploading (posting) larger entities (> 30/35mb): we start the streaming process and BEFORE it is finished our Post method on the Web API is hit, receiving a null entity.

我们不明白是怎么回事,并怀疑必须有相关的一些时间问题,因为这一切都取决于上传的大小。

We can't understand what is going on, and suspect there must be some timing issue related since it all depends on the size of the upload.

要进一步说明,我们在总结的客户是这样做的:

To further explain, our client in summary is doing this:

HttpResponseMessage response = await _client.SendAsync(request);
string jsonResult = await response.Content.ReadAsStringAsync();

...其中_client是我们HttpClient的,并要求我们的Htt prequestMessage。在情况下,它也关系(我尽量不产生大量code :)的问题,在请求的内容是这样创建:

... where _client is our HttpClient and request our HttpRequestMessage. In case it is also relevant (I am trying not to flood the question with code :), the content in the request is created like this:

request.Content = new StringContent(JsonConvert.SerializeObject(content), Encoding.UTF8, "application/json");

那么,当我们调试这是我们的服务器上的POST方法等待_client.SendAsync(要求)完成,其中一种解释为什么它被接受在这种情况下空实体(更大的实体)之前被击中,其中当它的工作原理是等待呼叫结束,然后张贴被击中。

Well, when we debug this the Post method on our server is hit before the await _client.SendAsync(request) finishes, which sort of "explains" why it is receiving a null entity in such cases (larger entities), where when it works that await call is finished and THEN the Post is hit.

在情况下,如果大棚更多的光线进入它,由于对HttpClient的某些限制(关于获取AllowWriteStreamBuffering),我们也测试了一个等效场景,而是直接使用HttpWebRequest的......不幸的是,该行为是完全一样的。这是有关摘要:

In case if sheds more light into it, due to certain limitations on the HttpClient (regarding access to AllowWriteStreamBuffering), we have also tested an equivalent scenario but using directly an HttpWebRequest... unfortunately, the behavior is exactly the same. This is the relevant extract:

httpRequest.BeginGetRequestStream(RequestStreamCallback, httpRequest);

(其中HTT prequest是我们的HttpWebRequest与AllowWriteStreamBuffering = FALSE),并处理请求流回调如下:

(where httpRequest is our HttpWebRequest with AllowWriteStreamBuffering = false), and the callback to handle the request stream is as follows:

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被击中(带有null参数)邮政法更大的实体之前,streamWriter.Write定型和streamWriter.Close被击中。

Again, for larger entities when we debug the Post method on the Web API is hit (with a null parameter) BEFORE the streamWriter.Write finalizes and the streamWriter.Close is hit.

我们一直在阅读所有的地方,并与这对现在的战斗了好几天。任何帮助将大大AP preciated!

We've been reading all over the place and fighting with this for days on now. Any help will be greatly appreciated!

推荐答案

在有人的情况下运行到这一点,我终于想通了事情的原委。

In case somebody runs into this, I finally figured out what was going on.

在本质上,反序列化的JSON当模型在Web API Post方法结合机制抛出一个异常,但例外是有点隐藏......至少,如果你不知道太多关于那个内在Web API的工作方式,因为是我的情况。

In essence, the model binding mechanism in the Web API Post method was throwing an exception when de-serializing the JSON, but the exception was somewhat "hidden"... at least if you did not know that much about the inner workings of the Web API, as was my case.

我Post方法最初缺乏此验证检查:

My Post method originally lacked this validation check:

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中的有效性......在我们的场景断是无效,因为Web API一直没能到实体绑定,原因可以在ModelState.Values​​的错误属性中找到。这一职位被击中确定,但有一个空的实体,如提及。

This is a "sample" check, the main idea being verifying the validity of the ModelState... in our breaking scenarios is wasn't valid because the Web API hadn't been able to bind the entity, and the reason could be found within the Errors properties of the ModelState.Values. The Post was being hit ok, but with a null entity, as mentioned.

顺便说一句,这个问题主要是由于这一事实,我们并没有真正的流媒体内容,但使用的是试图要全部取消序列化的StringContent ...但是,这是另一回事,我们主要关心这里不理解什么突破和地点。

By the way, the problem was mainly caused by the fact that we weren't really streaming the content, but using a StringContent which was attempted to be de-serialized in full... but that is another story, we were mainly concerned here with not understanding what was breaking and where.

希望这有助于。

这篇关于网页API后打之前的HttpWebRequest已完成流大文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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