为了账号安全,请及时绑定邮箱和手机立即绑定

.NET Core 2.1 DbContext ObjectDisposedException

.NET Core 2.1 DbContext ObjectDisposedException

C#
哆啦的时光机 2022-11-21 21:22:29
我正在使用 .NET Core 2.1 和 Entity Framework 制作一个 n 层 MVC 应用程序。还有一个托管的 MQTT 队列,我的应用程序在该队列上作为客户端进行侦听。我还使用依赖注入。这非常有效,直到一条消息被推送到队列并且我想将该消息保存到数据库。一旦发生这种情况,我会收到以下ObjectDisposedException错误消息:无法访问已处置的对象。此错误的一个常见原因是处理从依赖项注入解析的上下文,然后尝试在应用程序的其他地方使用相同的上下文实例。如果您在上下文中调用 Dispose() 或将上下文包装在 using 语句中,则可能会发生这种情况。如果您正在使用依赖注入,则应该让依赖注入容器负责处理上下文实例。对象名称:'xxxDbContext'。我可以单击继续,之后应用程序继续工作。他只在从队列收到的第一条消息上抛出异常。控制器/管理器/存储库的所有其他操作都可以正常工作。我的代码如下:启动.cspublic void ConfigureServices(IServiceCollection services){    services.AddDefaultIdentity<User>()            .AddEntityFrameworkStores<xxxDbContext>();    services.AddDbContext<xxxDbContext>(options =>        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")    ));    // Some identity configuration omitted here    services.AddScoped<IIdeationRepository, IdeationRepository>();    services.AddScoped<IIdeationManager, IdeationManager>();    // Some other DI configuration omitted as well.}public Configure(IApplicationBuilder app, IHostingEnvironment env,    IApplicationLifetime applicationLifetime, IServiceProvider serviceProvider){    // Start MQTT    var broker = new MqttBroker(serviceProvider.GetService<IIdeationManager>(),        serviceProvider.GetService<IConfiguration>());    // On application exit terminate MQTT to make sure the connection is ended properly    applicationLifetime.ApplicationStopping.Register(() => broker.Terminate());    // Some default http pipeline code omitted}MqttBroker.cspublic MqttBroker(    [FromServices] IIdeationManager ideationManage,    [FromServices] IConfiguration configuration){    _ideationManager = ideationManager;    _configuration = configuration;    Initialize();}    // Some code where I just parse the message and on receive send it to the    // ideation manager, this just works so I omitted it.}管理器只是将它直接发送到出现错误消息的存储库。
查看完整描述

2 回答

?
慕容3067478

TA贡献1773条经验 获得超3个赞

IServiceProvider传入的实例Configure是scoped,这意味着它在完成后由框架处理-它创建的Configure任何范围内的服务也会在此过程中处理。


在您的示例中,您正在请求一个实例IIdeationManager(它是scoped),然后尝试在您的MqttBroker类中使用它(实际上是一个singleton)。当您尝试使用 的实现时IIdeationManager,由 DI 创建和连接的范围实例已被释放,因此抛出异常。CityOfIdeasDbContextObjectDisposedException


为了解决这个问题,您可以采用在单例需要访问范围服务时使用的通用模式:创建范围、解析服务、使用服务,然后处置范围。松散地,这看起来有点像这样:


using (var scope = serviceProvider.CreateScope())

{

    var ideationManager = scope.ServiceProvider.GetService<IIdeationManager>();


    // Do something with ideationManager.

}


// scope and all created disposable services have been disposed.

当您请求实现 时IIdeationManager,DI 系统发现(最终)它需要一个作用域CityOfIdeasDbContext并为您创建一个。一旦scope被处置,这个CityOfIdeasDbContext实例也被处置。


为了使其在您的示例中起作用,您MqttBroker可以将 的 实例IServiceProvider带入其构造函数并使用它来创建我上面显示的范围(它仍然可以IConfiguration按原样使用,因为它本身是一个单例)。


应该传递给类的实例不IServiceProvider应该是传递给类的MqttBroker实例——这已经确定了范围,并且正如我所描述的那样,将在完成后清理,这确实是您开始时遇到的问题。为此,请使用,它是根提供者并且没有作用域。IServiceProviderConfigureConfigureapp.ApplicationServices


查看完整回答
反对 回复 2022-11-21
?
慕村225694

TA贡献1880条经验 获得超4个赞

我之前也遇到过同样的问题,我也曾尝试像 .net 经典分层结构存储库设计模式案例一样处理 dbcontext 对象,但在 .net 核心中足以使其范围解决问题。因为它针对每个请求进行处理,所以您不需要手动处理 dbcontext。此外,IServiceCollection 中的 adddbcontext 方法将其实现为默认范围。参考


查看完整回答
反对 回复 2022-11-21
  • 2 回答
  • 0 关注
  • 164 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信