Чтение 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"}
4 ответа:
по дизайну содержание тела внутри ASP.NET веб-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, поэтому он не будет рассматриваться как чтение содержимого).
вы можете сохранить свой контактный параметр со следующим подходом:
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 моего объекта параметра, поэтому я мог бы использовать его для обработки исключений и ведения журнала.
найдено как принятый ответ здесь
хотя это решение может показаться очевидным, я просто хотел опубликовать его здесь, чтобы следующий парень быстрее google.
Если вы все еще хотите иметь модель в качестве параметра в метод, вы можете создать
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());
Это решение основано на ответ by Даррел Миллер.
таким образом все запросы будут буферизованный.
самый простой способ прочитать содержимое любого запроса обычно заключается в использовании HTTP-прокси, например Саша
Это имеет огромное преимущество, показывая вам все локальный трафик (плюс полные запросы-заголовки и т. д.) и множество других запросов, которые читают содержимое запроса внутри конкретного действия в конкретном контроллере, не покажут вам - например, 401 / 404 и т. д.
вы также можете использовать композитора скрипача для создания тестовых запросов с нуля или путем изменения предыдущих запросов.
Если вы по какой-то причине не можете использовать прокси или должны просмотреть запрос изнутри веб-приложения, то ответ выглядит разумно