Невозможно прочитать поток ввода - PullRequest
0 голосов
/ 29 августа 2018

Я использую 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 он дает мне эту ошибку:

Доступ к BinaryRead, Form, Files или InputStream осуществлялся до того, как внутреннее хранилище было заполнено вызывающей стороной HttpRequest.GetBufferedInputStream.

И входной поток выдает эту ошибку

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/xml или application/x-www-form-urlencoded, он будет работать, но если я установлю его на application/json, это выдаст мне эту ошибку !!

Пожалуйста, сообщите!

Ответы [ 3 ]

0 голосов
/ 06 сентября 2018

Есть пара моментов:

Во-первых, если вы попытаетесь прочитать 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());
        }
     }

Кроме того, однажды я столкнулся с той же проблемой, и увеличение maxRequestLength в web.config, похоже, решило проблему. Эта ссылка также предоставляет дополнительную информацию здесь

0 голосов
/ 07 сентября 2018

Я могу ошибаться, но вот что я нашел. Фильтры действий выполняются после привязки модели, что означает, что поток запроса уже прочитан. В вашем случае я не уверен, что это значит. https://exceptionnotfound.net/the-asp-net-web-api-2-http-message-lifecycle-in-43-easy-steps-2/ подробно объясняет жизненный цикл. Изменение типа контента не изменило бы события жизненного цикла, а скорее изменило бы содержимое запроса, что, в свою очередь, могло бы повлиять на привязку модели. Если у вас установлена ​​модель для действия, тогда Как получить текущую модель в фильтре действия должно помочь. Таким образом, решение было бы получить объект модели из actionContext и затем изменить его соответствующим образом.

0 голосов
/ 04 сентября 2018

Это то, как я делаю это в моем связывателе моделей, но я не уверен, как это будет работать с вашим фильтром действий. Я проверил онлайн, и есть противоречивая информация; Некоторые говорят, что вы не можете прочитать входной поток, так как он не доступен для поиска, и 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
}
...