Чтение HttpContent в контроллере WebApi
Как я могу прочитать содержимое запроса PUT в действии контроллера MVC webApi.
[HttpPut]
public HttpResponseMessage Put(int accountId, Contact contact)
{
var httpContent = Request.Content;
var asyncContent = httpContent.ReadAsStringAsync().Result;
...
Я получаю пустую строку здесь: (
Что мне нужно сделать: выяснить, какие свойства были изменены/отправлены в первоначальном запросе (это означает, что если объект Contact
имеет 10 свойств, и я хочу обновить только 2 из них, я отправляю и объект с двумя свойствами, что-то вроде этого:
{
"FirstName": null,
"LastName": null,
"id": 21
}
Ожидаемый конечный результат
List<string> modified_properties = {"FirstName", "LastName"}
Ответы
Ответ 1
По дизайну содержимое тела в ASP.NET Web API рассматривается как прямой поток, который можно читать только один раз.
Первое чтение в вашем случае выполняется, когда веб-API привязывает вашу модель, после чего Request.Content
ничего не вернет.
Вы можете удалить contact
из своих параметров действия, получить контент и десериализовать его вручную в объект (например, с помощью Json.NET):
[HttpPut]
public HttpResponseMessage Put(int accountId)
{
HttpContent requestContent = Request.Content;
string jsonContent = requestContent.ReadAsStringAsync().Result;
CONTACT contact = JsonConvert.DeserializeObject<CONTACT>(jsonContent);
...
}
Это должно сделать трюк (предполагая, что accountId
является параметром URL, поэтому он не будет рассматриваться как чтение содержимого).
Ответ 2
Вы можете сохранить свой параметр CONTACT следующим образом:
using (var stream = new MemoryStream())
{
var context = (HttpContextBase)Request.Properties["MS_HttpContext"];
context.Request.InputStream.Seek(0, SeekOrigin.Begin);
context.Request.InputStream.CopyTo(stream);
string requestBody = Encoding.UTF8.GetString(stream.ToArray());
}
Вернул для меня json-представление объекта моего параметра, поэтому я мог использовать его для обработки исключений и регистрации.
Найдено как принятый ответ здесь
Ответ 3
Несмотря на то, что это решение может показаться очевидным, я просто хотел опубликовать его здесь, чтобы следующий парень быстрее выполнил его.
Если вы все еще хотите иметь модель в качестве параметра в методе, вы можете создать DelegatingHandler
для буферизации содержимого.
internal sealed class BufferizingHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
await request.Content.LoadIntoBufferAsync();
var result = await base.SendAsync(request, cancellationToken);
return result;
}
}
И добавьте его в глобальные обработчики сообщений:
configuration.MessageHandlers.Add(new BufferizingHandler());
Это решение основано на ответе Даррел Миллер.
Таким образом, все запросы будут буферизованы.
Ответ 4
Самый простой способ прочитать содержимое любого запроса - это использовать прокси-сервер http, например fiddler
Это имеет огромное преимущество в том, что вы показываете локальный трафик all (плюс полные запросы - заголовки и т.д.) и множество других запросов, которые считывают содержимое запроса внутри определенного действия в конкретном контроллере. показать вам - например 401/404 и т.д.
Вы также можете использовать композитор скрипача для создания тестовых запросов с нуля или путем изменения предыдущих запросов.
Если вы по какой-то причине не можете использовать прокси или должны просмотреть запрос из веб-приложения, то этот ответ выглядит разумно