ASP.NET Core 2.1 MVC-将每个请求记录到数据库

最后发布: 2019-01-02 15:41:14


问题

我想数据库记录我的应用程序处理每个请求所花费的时间,以及一些其他信息,例如接收到的每个请求的IP地址。

我已经在Startup.cs中添加了一个app.Use步骤->使用依赖注入配置到我的dbcontext。 当以下代码触发并且我的MVC管道似乎正确触发时,我没有收到任何错误。

问题是任何涉及dbcontext的调用似乎都退出了代码。 在下面的示例中, db.PageRequests.Add(pageRequest); 导致代码退出。 该页面仍然可以正常显示,但是当然会丢失任何附加到响应中的内容。

我忍不住认为这是一个异步/线程问题,但是我迷失了主意。 我还尝试了使dbcontext交互既同步又异步,但这无济于事。

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ApplicationDbContext db)
    {
        app.Use(async (context, next) =>
        {
            var sw = new Stopwatch();
            sw.Start();
            await next.Invoke();
            sw.Stop();

            PageRequest pageRequest = new PageRequest()
            {
                ipAddress = context.Connection.RemoteIpAddress.ToString(),
                loadTime = sw.ElapsedMilliseconds
            };
            db.PageRequests.Add(pageRequest);  // this code exits and page is rendered.  Code below here is never fired.
            db.SaveChanges();

            await context.Response.WriteAsync("<p>" + sw.ElapsedMilliseconds.ToString() + "<p>");
            await context.Response.WriteAsync("<p>" + context.Connection.RemoteIpAddress + "<p>");
            await context.Response.WriteAsync("<p>" + context.Request.Host + context.Request.Path + context.Request.QueryString + "<p>");

        });
    // other app.use statements here
    }
entity-framework logging asp.net-core-mvc configure asp.net-core-2.1
回答

我在Microsoft文档中找到一条注释,指出了正确的方向。

由于中间件是在应用启动时构建的,而不是根据每个请求构建的,因此中间件构造函数使用的作用域生存期服务不会在每次请求期间与其他依赖项注入类型共享。 如果必须在中间件和其他类型之间共享作用域服务,请将这些服务添加到Invoke方法的签名中。

我相信在应用程序启动后,注入到Configure方法中的dbcontext将不再可用,因此在每个请求期间都无法访问。 令人沮丧的是,这没有引发错误。

解决方案是将中间件委托移至一个类,并将上下文注入invoke方法。

这是对我有用的代码:

public class Logging
{
    private readonly RequestDelegate _next;

    public Logging(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context, ApplicationDbContext db)
    {
        var sw = new Stopwatch();
        sw.Start();
        await _next(context);
        sw.Stop();

        PageRequest pageRequest = new PageRequest()
        {
            ipAddress = context.Connection.RemoteIpAddress.ToString(),
            loadTime = sw.ElapsedMilliseconds
        };
        await db.PageRequests.AddAsync(pageRequest); 
        db.SaveChanges();

        await context.Response.WriteAsync("<p>" + sw.ElapsedMilliseconds.ToString() + "<p>");
        await context.Response.WriteAsync("<p>" + context.Connection.RemoteIpAddress + "<p>");
        await context.Response.WriteAsync("<p>" + context.Request.Host + context.Request.Path + context.Request.QueryString + "<p>");
    }

}

public static class LoggingMiddlewareExtensions
{
    public static IApplicationBuilder UseLogging(
        this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<Logging>();
    }
}`

然后可以将Use语句添加到Startup.cs-> Configure中。

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ApplicationDbContext db)
    {

        app.UseLogging();

    }