Чтение 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 57

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 и т. д.

вы также можете использовать композитора скрипача для создания тестовых запросов с нуля или путем изменения предыдущих запросов.

Если вы по какой-то причине не можете использовать прокси или должны просмотреть запрос изнутри веб-приложения, то ответ выглядит разумно