Не удалось прочитать входной поток
Я использую 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/xml
или application/x-www-form-urlencoded
оно будет работать, но если я его установлю в application/json
он даст мне эту ошибку!
Пожалуйста, порекомендуйте!
Ответы
Ответ 1
Есть несколько моментов:
Во-первых, если вы попытаетесь прочитать 0 байт из потока, тогда он выкинет исключение System.InvalidOperationException. Итак, я изменю свой код, как ContentLength > 0
ниже, и добавьте проверку 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, похоже, решило проблему. Эта ссылка дает дополнительную информацию здесь
Ответ 2
Вот как я это делаю внутри моего связующего объекта Model, но я не уверен, как он будет работать с вашим фильтром Action. Я проверил в Интернете и там противоречивую информацию; Некоторые говорят, что вы не можете прочитать входной поток, так как он не доступен для поиска, и 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
}
Ответ 3
Возможно, я ошибаюсь, но вот что я нашел. Фильтры действий выполняются после привязки модели, что означает, что поток запросов уже был прочитан. В вашем случае я не уверен, что это значит. https://exceptionnotfound.net/the-asp-net-web-api-2-http-message-lifecycle-in-43-easy-steps-2/ подробно объясняет жизненный цикл. Изменение типа контента не изменило бы события жизненного цикла, но скорее изменило бы содержимое запроса, которое, в свою очередь, могло бы повлиять на привязку модели. Если у вас есть набор моделей для действия, тогда вам следует помочь как получить текущую модель в фильтре действий. Таким образом, решение было бы получить объект модели из actionContext
и затем соответствующим образом изменить его.