无法读取输入流

时间:2018-08-29 09:48:08

标签: c# asp.net-web-api2 inputstream memorystream

我正在使用ActionFilterAttribute来获取请求,然后按如下所示命中控制器:

 public override void OnActionExecuting(HttpActionContext actionContext)
 {
     using (var stream = new MemoryStream())
     {
        HttpContextBase context = (HttpContextBase)actionContext.Request.Properties["MS_HttpContext"];
        context.Request.InputStream.Seek(0, SeekOrigin.Begin);
        context.Request.InputStream.CopyTo(stream);
        requestBody = Encoding.UTF8.GetString(stream.ToArray());
     }
 }

以上方法适用于较小的请求,但适用于较大的json,它给了我这个错误:

  

在HttpRequest.GetBufferedInputStream的调用者填充内部存储之前,已访问BinaryRead,Form,Files或InputStream。

输入流出现此错误

  

context.Request.InputStream抛出了System.InvalidOperationException类型的异常System.IO.Stream {System.InvalidOperationException}

正如我在研究中发现的那样,这是超时问题,但是我无法更改代码中的超时。我尝试更改web.config文件maxRequestLength="102400000"maxAllowedContentLength="209715100"中的值,但仍然遇到相同的错误。
如果我读了GetBufferedInputStream但还是同样的问题,那就是读缓冲区的一部分,而不是整个流。

我还尝试了以下方法:

 Stream InStream;
 int Len;
 InStream = HttpContext.Current.Request.InputStream;
 Len = System.Convert.ToInt32(InStream.Length);
 byte[] ByteArray = new byte[Len + 1];
 InStream.Seek(0, SeekOrigin.Begin);
 InStream.Read(ByteArray, 0, Len);
 var jsonParam = System.Text.Encoding.UTF8.GetString(ByteArray); 

请注意,如果我将内容类型设置为application/xmlapplication/x-www-form-urlencoded,那么它将起作用,但是如果将其设置为application/json,则会出现此错误!

请告知!

3 个答案:

答案 0 :(得分:3)

有两点:

首先,如果您尝试从流中读取0个字节,则它将引发System.InvalidOperationException异常。因此,我将像下面那样更改您的代码,并为ContentLength > 0添加一个检查。

using (var stream = new MemoryStream())
     {
        HttpContextBase context = (HttpContextBase)actionContext.Request.Properties["MS_HttpContext"];
        if(context.Request.Contentlength > 0)
        {
            context.Request.InputStream.Seek(0, SeekOrigin.Begin);
            context.Request.InputStream.CopyTo(stream);
            requestBody = Encoding.UTF8.GetString(stream.ToArray());
        }
     }

此外,我曾经遇到过同样的问题,在web.config中增加maxRequestLength似乎可以解决该问题。 该链接进一步提供了更多信息here

答案 1 :(得分:2)

这是我在模型资料夹中执行的操作,但是我不确定它如何与您的“动作”过滤器一起使用。我在网上检查过,发现信息冲突;有人说您无法读取输入流,因为它不可搜索,并且ASP.NET需要读取它以绑定模型。有人说这确实是可寻找的,并使用您上面共享的方法。因此,找出确实有效的方法的唯一方法就是进行测试。

我希望我的代码示例可以帮助您解决问题。

object request = null;
if (actionContext.Request.Method == HttpMethod.Post && "application/json".Equals(actionContext.Request.Content.Headers.ContentType.MediaType))
{
    var jsonContentTask = actionContext.Request.Content.ReadAsStringAsync();
    Task.WaitAll(jsonContentTask);
    string jsonContent = jsonContentTask.Result;
    //... other stuff
}

答案 2 :(得分:1)

我可能是错的,但这是我发现的。在模型绑定之后执行动作过滤器,这意味着请求流已经被读取。就您而言,我不确定这意味着什么。 this article详细说明了生命周期。更改内容类型不会更改生命周期事件,而是会更改请求内容,从而可能影响模型绑定。 如果您为操作设置了模型,那么https://exceptionnotfound.net/the-asp-net-web-api-2-http-message-lifecycle-in-43-easy-steps-2/应该会有所帮助。因此解决方案是从actionContext获取模型对象,然后相应地对其进行修改。