Как я могу прочитать тело запроса в проекте .Net 5 Webapi с помощью фильтра действий

Используя .Net 5 WebApi, у меня есть фильтр действий, и я пытаюсь просто прочитать тело запроса, но когда я читаю request.body, тело всегда пусто.

Как я могу прочитать текст тела запроса OnActionExecuting (например, Debug.Write(body)) и не быть пустым?

Мой пользовательский фильтр:

public class MyCustomFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        // Do something before the action executes.
        Debug.Write(MethodBase.GetCurrentMethod(), context.HttpContext.Request.Path);

        var bodyStream = context.HttpContext.Request.BodyReader.AsStream(true);

        using (var reader = new StreamReader(bodyStream))
        {
            var body = reader.ReadToEnd();

            Debug.Write(body);
        }
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        // Do something after the action executes.
        Debug.Write(MethodBase.GetCurrentMethod(), context.HttpContext.Request.Path);
    }
}

Мой контроллер API:

[ServiceFilter(typeof(MyCustomFilter))]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    private readonly ILogger<WeatherForecastController> _logger;

    public WeatherForecastController(ILogger<WeatherForecastController> logger)
    {
        _logger = logger;
    }

    [HttpPost]
    public IEnumerable<WeatherForecast> Post([FromBody] SomeData someData)
    {
        var rng = new Random();
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = rng.Next(-20, 55),
            Summary = Summaries[rng.Next(Summaries.Length)]
        })
        .ToArray();
    }
}

Startup.cs

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        services.AddScoped<MyCustomFilter>();
    }

Объект SomeData

public class SomeData
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Json, который я публикую

{
  "id": 1,
  "name": "test thing"
}

person user14256351    schedule 06.02.2021    source источник
comment
Краткий ответ: вы не можете (вернее: вы не должны). Вы не должны читать тело запроса в IActionFilter, потому что, если вы читаете поток запроса в IActionFilter, остальная часть приложения не может прочитать тело запроса, если вы не скопируете его в новый буфер, что делает ваше приложение уязвимым для отказа. of-service от чрезмерного использования памяти, если вы не будете осторожны. Вместо этого используйте промежуточное ПО.   -  person Dai    schedule 06.02.2021
comment
Это правда... и действительно правильный ответ. Спасибо. Поскольку я не могу пометить комментарий как правильный ответ, и моя цель состояла в том, чтобы добраться до модели, которая была передана, я исключаю @Yinqiu, но спасибо вам обоим за ваши ответы.   -  person user14256351    schedule 06.02.2021
comment
Могу я спросить, почему вы использовали [ServiceFilter(typeof(MyCustomFilter))]? вы не используете DI в фильтре действий   -  person Royi Namir    schedule 26.04.2021


Ответы (1)


Модель можно получить непосредственно в фильтре действий, как показано ниже.

public void OnActionExecuting(ActionExecutingContext context)
    {
        var body = context.ActionArguments["someData"] as SomeData ;
    }

Результат теста: введите здесь описание изображения

person Yinqiu    schedule 06.02.2021
comment
Позволит ли он прочитать его позже в самом действии снова? - person Royi Namir; 26.04.2021