如何在 ASP.NET Core WebAPI 中将其转换为 C# 控制器类之前读取 json 正文?

How to read json body, before it's converted into C# controller class in ASP.NET Core WebAPI?

提问人:Adam Wojnar 提问时间:11/16/2023 更新时间:11/16/2023 访问量:107

问:

拥有这个简单的端点:

[HttpPost]
public async Task<IActionResult> CreateUser([FromBody] UserInput userInput)
{
    if (userInput == null) return BadRequest();
    var userOutput = await _userService.AddUser(userInput);
    return CreatedAtRoute("GetUser", new { userId = userOutput.UserId }, userOutput);
}

如何检索已发送的确切 json?

就像现在一样,json 输入中的所有字段都必须在类中实现。我想知道在将原始身体转换为类之前,是否还有一种方法可以捕获原始身体UserInputUserInput

感谢您的帮助!

c# net-core asp.net-core-webapi

评论

0赞 Ibram Reda 11/16/2023
是的,有一种方法可以在端点中访问 JSON 内容(请参阅我的回答)。我认为没有理由需要这样做,因为我们可爱的框架为我们做了繁重的工作,并反序列化了内容,并为我们提供了一个漂亮的模型,可以使用,而不仅仅是JSON字符串
0赞 Adam Wojnar 11/16/2023
@IbramReda 出于日志记录目的,我需要准确记录正在发送的内容。如果模型中未定义某些内容,则将忽略该内容
0赞 Ibram Reda 11/16/2023
出于日志记录目的,您不需要访问 Endpoint 本身的 JSON,而是可以添加 HTTP 日志记录中间件......就像@Denis的回答一样
0赞 Denis Micheal 11/16/2023
@AdamWojnar 为什么不使用默认的 Asp 网核心 HTTP 日志记录中间件来捕获这些日志?
0赞 Adam Wojnar 11/22/2023
@DenisMicheal好吧,从技术上讲,这不是日志记录。我需要将传入的内容完全按原样保存在数据库中。然后将其转换为 C# 类并继续执行更多逻辑。因此,它就像常规端点一样,但需要注意的是,原始输入必须存储在数据库中。

答:

2赞 Denis Micheal 11/16/2023 #1

您可以使用 HttpLogging 中间件来捕获此请求信息

HTTP 日志记录是一个中间件,用于记录有关传入 HTTP 的信息 请求和 HTTP 响应。HTTP 日志记录提供以下日志:

HTTP 请求信息 通用属性 标头 正文 HTTP 响应 信息

非常容易配置和设置,您可以添加任何请求头、响应头等来记录

builder.Services.AddHttpLogging(logging =>
{
    logging.LoggingFields = HttpLoggingFields.All;
    logging.RequestHeaders.Add("sec-ch-ua");
    logging.ResponseHeaders.Add("MyResponseHeader");
    logging.MediaTypeOptions.AddText("application/javascript");
    logging.RequestBodyLogLimit = 4096;
    logging.ResponseBodyLogLimit = 4096;

});

通过在 Your 中调用 this 将其添加到管道中:Program.cs

app.UseHttpLogging();

并将其添加到您的logLevelappsettings.json

"Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information"

2赞 Ibram Reda 11/16/2023 #2

获取实际的 JSON 正文 当您在 中使用 Model Binding 时。NET5以上,有点棘手

首先,将此扩展方法添加到您的解决方案中,使我们的生活更轻松

public static async Task<string> GetRawBodyAsync(
    this HttpRequest request,
    Encoding encoding = null)
{
    if (!request.Body.CanSeek)
    {
        // We only do this if the stream isn't *already* seekable,
        // as EnableBuffering will create a new stream instance
        // each time it's called
        request.EnableBuffering();
    }

    request.Body.Position = 0;

    var reader = new StreamReader(request.Body, encoding ?? Encoding.UTF8);

    var body = await reader.ReadToEndAsync().ConfigureAwait(false);

    request.Body.Position = 0;

    return body;
}

我们需要在映射控制器/端点之前在管道中添加小型中间件,以使此方法正常工作

app.Use(next => context => {
    context.Request.EnableBuffering();
    return next(context);
});

现在,您可以在操作中获取 JSON 正文请求,如下所示

 [HttpPost]
 public async Task<IActionResult> CreateUser([FromBody] UserInput userInput)
 {
     string rawRequestBody = await Request.GetRawBodyAsync(); //<<< get your json as string

     if (userInput == null) return BadRequest();
     var userOutput = await _userService.AddUser(userInput);
     return CreatedAtRoute("GetUser", new { userId = userOutput.UserId }, userOutput);
 }

更多解释可以在 ASP.NET Core 中将原始请求正文读取为字符串中找到