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();
}
我想在数据库中记录我的应用程序处理每个请求所花费的时间,以及一些其他信息,例如收到的每个请求的 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();
}