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

Как получить контент, который уже прочитан

У меня есть класс, который наследуется от ApiController. У него есть метод Put-like:

[PUT("user/{UserId}")]
public HttpResponseMessage Put(string userId, PaymentRequest paymentRequest)
{
    // Calling business logic and so forth here
    // Return proper HttpResponseMessage here
}

Метод работает нормально, поскольку он выше. Теперь мне нужно проверить подпись вызова метода, но здесь я столкнулся с проблемой. Подпись, по сути, представляет собой комбинацию метода + url + body. Метод, который я могу получить, вызвав Request.Method и url, который я могу получить, вызвав Request.RequestUri.ToString(), но я не могу схватить тело, поскольку он был до, он был автоматически десериализован в объект PaymentRequest с помощью инфраструктуры asp.net MVC4.

Моя первая попытка: Как я теперь понял Request.Content.ReadAsStringAsync(). Результат ничего не возвращает. Это связано с тем, что содержимое можно прочитать только один раз.

Моя вторая попытка: Я попытался преобразовать его в строку JSON.

var serializer = new JavaScriptSerializer();
var paymentRequestAsJson = serializer.Serialize(paymentRequest);

Проблема заключается в том, что форматирование оказывается немного отличным от основной части сигнатуры. Он имеет те же данные, но еще несколько пробелов.

Я не могу изменить то, что делает caller моего метода Put, так как это сторонний компонент. Что мне делать?

4b9b3361

Ответ 1

Вы можете прочитать из основного запроса:

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());
}

Ответ 2

Не включайте параметр body в подпись, и это позволит вам буферизовать содержимое и читать содержимое столько раз, сколько захотите.

[PUT("user/{UserId}")]
public HttpResponseMessage Put(string userId)
{
    Request.Content.LoadIntoBufferAsync().Wait();
    var paymentRequest = Request.Content.ReadAsAsync<PaymentRequest>().Result;
    var requestBody = Request.Content.ReadAsStringAsync().Result;
    // Calling business logic and so forth here
    // Return proper HttpResponseMessage here
}

Ответ 3

Очень отсроченный ответ, но в последнее время мне пришлось преодолеть такую ​​же проблему.

Я подошел немного по-другому, не получая данные из httpContext (может быть довольно дорогостоящим для веб-приложения с большими объемами транзакций).

Я создал простой интерфейс и сделал каждый его контроллер:

public interface IBaseControllerData
{
    object Entity { get; set; }
}

Затем я установил свойство Controller Entity в полезную нагрузку Json для каждого сообщения и поместил действие. Наконец, я получил данные Entity в ActionFilterAttribute.OnActionExecuted переопределенном методе и сериализовал его в Json перед введением в MongoDB:

object entity = ((IBaseControllerData)actionExecutedContext.ActionContext.ControllerContext.Controller).Entity;
                    requestBody = Newtonsoft.Json.JsonConvert.SerializeObject(entity);

Надеюсь, что это поможет!

Приветствия