Подтвердить что ты не робот

Чтение 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"}
4b9b3361

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

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

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