You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# ASP.NET异步方法依赖注入对象已释放异常问题求助

ASP.NET中Discord.Net事件触发异步方法时IServiceProvider已释放的问题解决

问题现象

在C# ASP.NET服务中调用依赖项时触发以下错误:

CG10.Bot.DiscordSender[0]
System.ObjectDisposedException: 无法访问已释放的对象。
对象名: 'IServiceProvider'。
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ThrowHelper.ThrowObjectDisposedException()
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
at CG10.Bot.DiscordSender.SlashCommandHandler(SocketSlashCommand command) in E:\SERVER\CG10Website\Bot\DiscordSender.cs:line 261

自定义的非异步Initialize方法中依赖项可正常工作,但所有由Discord.Net包事件处理器触发的异步方法均无法运行,涉及SQL数据库或尝试使用IServiceManager修复的场景。

相关代码

服务注册(Program文件)

builder.Services.AddScoped<IDiscordSender, DiscordSender>();

构造函数注入代码

public DiscordSender(
            UserManager<IdentityUser> userManager,
            RoleManager<IdentityRole> roleManager,
            IUnitOfWork db,
            TFDbContext tfdb,
            ILogger<DiscordSender> logger, ILogger<SlashCommand> loggerOther, IMemoryCache memoryCache, IServiceProvider service)
        {
            _roleManager = roleManager;
            _userManager = userManager;
            _db = db;
            _tfdb = tfdb;
            _logger = logger;
            _loggerOther = loggerOther;
            _memoryCache = memoryCache;
            _service = service;
        }

出错的异步方法代码

public async Task SlashCommandHandler(SocketSlashCommand command)
        {
            try
            {
                _db = _service.GetService<IUnitOfWork>(); //此处崩溃,进入捕获块
                if (_db == null)
                {
                    _logger.LogCritical("Failed to receive IUnitOfWork service");
                    return;
                }
            //后续代码已省略

已尝试将异步方法返回值从Void改为Task,但问题仍未解决。

解决方案

核心原因

DiscordSender是Scoped生命周期服务,其构造函数注入的IServiceProvider实际绑定到当前请求的服务作用域。当Discord.Net的事件触发时,原请求作用域已经被释放,导致IServiceProvider无法使用。

修复步骤

  1. 注入IServiceScopeFactory替代直接注入IServiceProvider
    修改构造函数,替换依赖注入的服务类型:

    private readonly IServiceScopeFactory _serviceScopeFactory;
    
    public DiscordSender(
                UserManager<IdentityUser> userManager,
                RoleManager<IdentityRole> roleManager,
                IUnitOfWork db,
                TFDbContext tfdb,
                ILogger<DiscordSender> logger, ILogger<SlashCommand> loggerOther, IMemoryCache memoryCache, IServiceScopeFactory serviceScopeFactory)
            {
                _roleManager = roleManager;
                _userManager = userManager;
                _db = db;
                _tfdb = tfdb;
                _logger = logger;
                _loggerOther = loggerOther;
                _memoryCache = memoryCache;
                _serviceScopeFactory = serviceScopeFactory;
            }
    
  2. 在异步方法中创建独立作用域获取服务
    在事件触发的异步方法内,创建新的服务作用域,从该作用域中获取所需服务,并通过using语句确保作用域自动释放:

    public async Task SlashCommandHandler(SocketSlashCommand command)
            {
                try
                {
                    using var scope = _serviceScopeFactory.CreateScope();
                    var db = scope.ServiceProvider.GetRequiredService<IUnitOfWork>();
                    // 使用db执行数据库操作及其他业务逻辑
                    // 后续代码...
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "处理Slash命令时出错");
                }
            }
    
  3. 移除对全局_db字段的复用
    不要复用构造函数中注入的IUnitOfWork实例(它属于原请求作用域,会随作用域释放而失效),每次事件触发时都从新作用域获取独立的服务实例。

额外说明

  • Scoped服务的生命周期与请求上下文绑定,而Discord.Net的事件在请求上下文之外触发,必须创建独立作用域来管理服务的生命周期。
  • 使用using语句可以确保服务作用域在使用完成后自动释放,避免资源泄漏。

内容的提问来源于stack exchange,提问作者cadergator10

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 09:27:25