[英]ObjectDisposedException when trying to write to database inside request pipeline
I am trying to add some code that will save a DateTime value to database on every request. 我正在尝试添加一些代码,以将每个请求的DateTime值保存到数据库。
I added some code to Configure method with app.Use()
. 我向
app.Use()
Configure方法添加了一些代码。
This is my configure method: 这是我的配置方法:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, MyDbContext db)
{
var appSettings = Configuration.GetSection("AppSettings").Get<AppSettings>();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors(builder =>
builder.WithOrigins(appSettings.BaseUrls.WebAllowCors)
.AllowAnyHeader().AllowAnyMethod()
);
app.UseAuthentication();
app.Use(async (context,next) =>
{
var id = context.User.Claims.First(x => x.Type == "sub").Value;
var user = db.AspNetUsers.Find(id);
user.LastAccessed = DateTime.Now;
await db.SaveChangesAsync();
await next();
});
app.UseMvc();
}
But I get the error: 但是我得到了错误:
An unhandled exception occurred while processing the request.
处理请求时发生未处理的异常。
ObjectDisposedException: Cannot access a disposed object.
ObjectDisposedException:无法访问已处置的对象。 A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application.
导致此错误的常见原因是,处理从依赖项注入中解决的上下文,然后稍后尝试在应用程序中的其他位置使用相同的上下文实例。 This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement.
如果在上下文上调用Dispose()或将上下文包装在using语句中,则可能会发生这种情况。 If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
如果使用依赖项注入,则应让依赖项注入容器负责处理上下文实例。 Object name: 'MyDbContext'.
对象名称:“ MyDbContext”。
What is correct way here to write to database on every request? 在每个请求上写入数据库的正确方法是什么?
this can happen because you are using the scope wrong. 发生这种情况是因为您使用的示波器不正确。 You are getting the db instance from your configure method.
您正在从configure方法获取数据库实例。 But this is called once at the startup.
但这在启动时被调用一次。
You should do something like this: 您应该执行以下操作:
app.Use(async (context, next) =>
{
var id = context.User.Claims.First(x => x.Type == "sub").Value;
using(var db = context.RequestServices.GetService<MyDbContext>())
{
var user = db.AspNetUsers.Find(id);
user.LastAccessed = DateTime.Now;
await db.SaveChangesAsync();
}
await next();
});
Hope this snippet helps you. 希望此代码段对您有所帮助。 If you need any clarification i would be more than willing to answer your questions.
如果您需要任何澄清,我将很乐意回答您的问题。
There can be multiple ways to handle this situation. 可以有多种方法来处理这种情况。 One that i would go with, is creating custom filters and annotating the methods or operations with a custom filter to update user's last access time.
我会使用的一个方法是创建自定义过滤器,并使用自定义过滤器注释方法或操作以更新用户的上次访问时间。
public class UpdateLastAccessFilter : ActionFilterAttribute, IActionFilter
{
void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext)
{
// TODO: Add your action filter's tasks here
// Log Action Filter call
using (dbEntities context = new dbEntities())
{
var id = context.User.Claims.First(x => x.Type == "sub").Value;
var user = db.AspNetUsers.Find(id);
user.LastAccessed = DateTime.Now;
await db.SaveChangesAsync();
OnActionExecuting(filterContext);
}
}
}
and then decorate the methods or controllers for which you need to log access time. 然后装饰您需要记录访问时间的方法或控制器。
[UpdateLastAccessFilter]
public class StoreController : Controller
{
...
}
This may be because MyDbContext
is disposable and needs to be wrapped in a using every time you need it. 这可能是因为
MyDbContext
是可抛弃的,并且每次需要时都需要包装在MyDbContext
中。
Try this and see if it works: 试试看,看看是否可行:
using (var context = db)
{
context.AspNetUsers.Find(id);
}
You may need to do the same with any subsequent use of db
. 您可能需要对
db
任何后续使用执行相同的操作。
I'm assuming that MyDbContext
has been registered to the IoC in the StartUp.cs
ConfigureService(IServiceCollection services)
function? 我假设
MyDbContext
已在StartUp.cs
ConfigureService(IServiceCollection services)
函数中注册到IoC? Something like this: 像这样:
services.AddDbContext<MyDbContext>(options =>
options.UseSqlServer(Configuration.GetSection("ConnectionStrings:Sql").Value)
);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.