如何使用Serilog访问控制器接口接收的模型参数中的属性值
Serilog 读取请求模型属性的实现方案
方案1:控制器内手动记录(最便捷)
直接在端点对应的Action方法中,参数绑定完成后直接读取Person.Name写入日志即可,不需要额外配置:
[HttpPost("x")] public IActionResult EndpointX(Person person) { // 直接将Name属性写入日志事件 Log.Information("接收端点X请求,提交人姓名:{PersonName}", person.Name); // 如果需要后续所有日志都携带该属性,可推入日志上下文 using (LogContext.PushProperty("RequestPersonName", person.Name)) { // 此处编写业务逻辑,该范围内的所有Serilog日志都会自动带上RequestPersonName字段 } return Ok(); }
方案2:动作过滤器全局/局部注入(无业务侵入)
通过实现ASP.NET Core的IAsyncActionFilter过滤器,直接读取模型绑定完成后的参数,不需要自行解析请求体,适配所有参数提交格式(JSON、表单、路由参数等):
- 首先自定义过滤器:
public class PersonNameLogFilter : IAsyncActionFilter { public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { // 从Action已绑定的参数中取出Person对象 if (context.ActionArguments.TryGetValue("person", out var personVal) && personVal is Person person) { // 将Name推入全局日志上下文 LogContext.PushProperty("RequestPersonName", person.Name); } await next(); } }
- 然后给需要的端点加上特性即可:
[HttpPost("x")] [TypeFilter(typeof(PersonNameLogFilter))] public IActionResult EndpointX(Person person) { // 业务代码 }
如果需要全局生效,直接在Program.cs中注册过滤器即可,不需要给每个端点加特性。
方案3:自定义中间件全局解析(适配全链路日志场景)
如果需要在请求进入控制器之前就拿到Name属性,可自定义中间件读取请求体解析,注意要开启请求体可重复读,避免后续模型绑定失败:
// Program.cs中添加中间件,要放在路由匹配之后,控制器执行之前 app.Use(async (context, next) => { // 启用请求体可重复读取 context.Request.EnableBuffering(); // 匹配目标端点 if (context.Request.Path.StartsWithSegments("/api/x")) { using var reader = new StreamReader(context.Request.Body, leaveOpen: true); var bodyContent = await reader.ReadToEndAsync(); var person = System.Text.Json.JsonSerializer.Deserialize<Person>(bodyContent); if (person != null) { LogContext.PushProperty("RequestPersonName", person.Name); } // 重置请求体流位置,供后续模型绑定读取 context.Request.Body.Position = 0; } await next(); });
内容的提问来源于stack exchange,提问作者Andrei Fulea
相关产品推荐
相关产品推荐

