Почему тело запроса Web API читается один раз?
Моя цель - аутентифицировать запросы веб-API с помощью AuthorizationFilter или DelegatingHandler. Я хочу найти идентификатор клиента и токен аутентификации в нескольких местах, включая тело запроса. Сначала казалось, что это будет легко, я мог бы сделать что-то вроде этого
var task = _message.Content.ReadAsAsync();
task.Wait();
if (task.Result != null)
{
// check if credentials are valid
}
Проблема в том, что HttpContent может быть прочитан только один раз. Если я делаю это в обработчике или фильтре, то содержимое нене доступно для меня в моем методе действия. Я нашел несколько ответов здесь в StackOverflow, как этот:Читать HttpContent в контроллере WebApi которые объясняют, что так сделано намеренно, но несказать почему. Это кажется довольно серьезным ограничением, которое не позволяет мне использовать какой-либо классный код синтаксического анализа контента Web API в Filters или Handlers.
Это техническое ограничение? Это пытается удержать меня от ОЧЕНЬ ПЛОХОГО (ТМ), что яя не вижу?
POSTMORTEM:
Я посмотрел на источник, как предложил Филипп. ReadAsStreamAsync возвращает внутренний поток и тамНичто не мешает вам позвонитьесли поток поддерживает это, В моих тестах, если я вызвал ReadAsAsync, то сделал это:
message.Content.ReadAsStreamAsync().ContinueWith(t => t.Result.Seek(0, SeekOrigin.Begin)).Wait();
Процесс автоматического связывания модели будет работать нормально, когда он коснется моего метода действия. Я не'Хотя я не могу использовать это, я выбрал что-то более прямое:
var buffer = new MemoryStream(_message.Content.ReadAsByteArrayAsync().WaitFor());
var formatters = _message.GetConfiguration().Formatters;
var reader = formatters.FindReader(typeof(Credentials), _message.Content.Headers.ContentType);
var credentials = reader.ReadFromStreamAsync(typeof(Credentials), buffer, _message.Content, null).WaitFor() as Credentials;
С методом расширения (I 'м. .NET 4.0 без ключевого слова await)
public static class TaskExtensions
{
public static T WaitFor(this Task task)
{
task.Wait();
if (task.IsCanceled) { throw new ApplicationException(); }
if (task.IsFaulted) { throw task.Exception; }
return task.Result;
}
}
Последний улов, HttpContent имеет жестко заданный максимальный размер буфера:
internal const int DefaultMaxBufferSize = 65536;
Так что, если ваш контент будет больше, чем выВам нужно будет вручную вызвать LoadIntoBufferAsync с большим размером, прежде чем пытаться вызвать ReadAsByteArrayAsync.