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

ASP.NET Core 2.1 MVC - Log Each Request to Database

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

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

问题是任何涉及 dbcontext 的调用似乎都会退出代码。在下面的示例中,db.PageRequests.Add(pageRequest); 导致代码退出。该页面仍然呈现良好,但当然缺少附加到响应的任何内容。

我不禁认为这是一个 async/threading 问题,但我却一头雾水。我还尝试使 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
    }

我在 Microsoft Documentation 中找到一条评论,为我指明了正确的方向。

Because middleware is constructed at app startup, not per-request, scoped lifetime services used by middleware constructors aren't shared with other dependency-injected types during each request. If you must share a scoped service between your middleware and other types, add these services to the Invoke method's signature.

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

解决方案是将中间件委托移动到 class 并在调用方法中注入上下文。

这是对我有用的代码:

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();

    }