You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.Net MVC5中Serilog LogContext.PushProperty在OWIN中间件失效问题

ASP.NET MVC5 OWIN中间件中Serilog LogContext属性丢失问题解决

问题原因

OWIN中间件的Invoke方法里,LogContext.PushProperty返回的IDisposable作用域会在方法执行完毕后自动释放。而MVC控制器的请求处理是在OWIN管道执行完成后异步触发的,此时原有的LogContext上下文已经失效,导致控制器日志无法获取到RequestId。

解决方案

1. 确认Serilog配置启用LogContext增强

首先确保Serilog初始化时添加Enrich.FromLogContext(),否则LogContext中的属性不会被注入到日志中:

Log.Logger = new LoggerConfiguration()
    .Enrich.FromLogContext()
    .WriteTo.Trace()
    .CreateLogger();

2. 跨OWIN与MVC上下文传递RequestId

因为OWIN和MVC的执行上下文在异步场景下不共享,需要通过HttpContext.Items中转RequestId,再用MVC的ActionFilter在控制器执行前重建LogContext作用域。

2.1 修改SerilogMiddleware存储RequestId

public class SerilogMiddleware
{
    private readonly Func<IDictionary<string, object>, Task> _next;

    public SerilogMiddleware(Func<IDictionary<string, object>, Task> next)
    {
        _next = next;
    }

    public async Task Invoke(IDictionary<string, object> environment)
    {
        var requestId = "123";
        // 将RequestId存入HttpContext.Items,供后续MVC环节读取
        HttpContext.Current.Items["RequestId"] = requestId;

        using (LogContext.PushProperty("RequestId", requestId))
        {
            Log.Information("Middleware log: Request processed");
            await _next(environment);
        }
    }
}

2.2 编写MVC ActionFilter重建LogContext

public class SerilogRequestIdFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext.HttpContext.Items.TryGetValue("RequestId", out var requestId))
        {
            // 在控制器执行前推入RequestId到LogContext,作用域覆盖整个Action执行过程
            using (LogContext.PushProperty("RequestId", requestId))
            {
                base.OnActionExecuting(filterContext);
            }
        }
        else
        {
            base.OnActionExecuting(filterContext);
        }
    }
}

2.3 注册全局ActionFilter

打开App_Start\FilterConfig.cs,将过滤器添加到全局集合:

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
        filters.Add(new SerilogRequestIdFilter());
    }
}

3. 验证结果

修改HomeController的日志代码后运行项目:

public ActionResult Index()
{
    Log.Information("Controller log: Index action executed");
    return View();
}

此时控制器日志会正确携带RequestId: 123,与中间件日志保持一致。

如果不想自定义实现,也可以直接使用Serilog.Web.Classic NuGet包,它内置了RequestId自动增强功能,无需手动编写中间件和过滤器。

内容的提问来源于stack exchange,提问作者Jonas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 02:55:27