C# 如何使用依赖项注入(DI)调用类 描述

C# 如何使用依赖项注入(DI)调用类 描述,c#,dependency-injection,blazor,webassembly,blazor-webassembly,C#,Dependency Injection,Blazor,Webassembly,Blazor Webassembly,我想用依赖项注入创建一个类的对象。如果手动设置参数,则会出现异常无法访问已处置的对象。 此应用程序是一个Blazor wasm,具有Dotnet core 3.1。我已经创建了一个应该连接到查询控制台的中间件。所以我有一个包含所有查询客户机的静态列表。如果缺少客户端,将创建该客户端 在中间件中调用异步: Startup.cs public void配置服务(IServiceCollection服务) { services.AddDbContext(选项=> option.UseMySql( Co

我想用依赖项注入创建一个类的对象。如果手动设置参数,则会出现异常
无法访问已处置的对象。

此应用程序是一个Blazor wasm,具有Dotnet core 3.1。我已经创建了一个应该连接到查询控制台的中间件。所以我有一个包含所有查询客户机的静态列表。如果缺少客户端,将创建该客户端

在中间件中调用异步:

Startup.cs

public void配置服务(IServiceCollection服务)
{
services.AddDbContext(选项=>
option.UseMySql(
Configuration.GetConnectionString(“DefaultConnection”),
mySqlOptions=>mySqlOptions.ServerVersion(新的System.Version(10,4,13),ServerType.MariaDb)
)
);
services.addScope();
services.addScope();
我试过的
  • 我曾尝试与服务提供商一起创建该类,但出现了相同的错误
  • 我已尝试使用创建的类中的服务提供程序创建缺少的参数。但我需要注入服务提供程序,该服务提供程序也会创建异常
    无法访问已处置的对象。对象名称:“IServiceProvider”。
  • 我已尝试使服务提供商处于静态状态,因此它无法被处置,但已被处置

  • 似乎
    IServiceProvider
    的实例是,并且在作用域结束时(我假设是在请求结束时)会处理该实例。您可以尝试为
    TeamspeakInstanceQueryClient
    定义单例工厂并使用它:

    class ClientFactory
    {
        private IServiceProvider _sp { get; set; }        
        private IServiceScope _scope  { get; set; }
        public  MyClass(IServiceProvider sp)
        {
            _sp = sp;
            _scope = sp.CreateScope();
        }
        public TeamspeakInstanceQueryClient Create() => new TeamspeakInstanceQueryClient(_scope.ServiceProvider);
    }
    
    // register it as singleton 
    services.AddSingleton<ClientFactory>();
    

    另外,此代码可以大大改进,并且仅用于演示目的。

    看起来它无法工作,因为存储库有EF Dbcontext。我发现此错误=>System.InvalidOperationException:无法解析作用域服务“Microsoft.EntityFrameworkCore.DbContextOptions`1[PhoenixBot.Server.ApplicationDbContext]'来自根提供程序。您可以创建子作用域并将其存储在factory中并使用它。请参阅更新的帖子。根据实际情况,您可能需要根据
    TeamspeakInstanceQueryClient
    创建作用域。看起来它起了作用。但仅供参考。此工厂创建了一个新的“终生作用域容器”哪一个创建了作用域DI?@LukasGund有作用域的概念。singleton使用
    服务的根构建。BuildServiceProvider()
    ,然后它可以创建作用域-通常的情况之一是每个web服务请求一个,每个作用域将共享
    作用域
    服务(所以在作用域内,您将始终获得相同的作用域服务)。当作用域结束时,它将处理所有实现
    IDIsposable
    的实例化作用域服务和临时服务(一般情况下,其他一些容器也可能具有不同的行为)。为什么您的
    TeamspeakInstanceQueryClient
    类创建
    InstancesControlRepository
    的实例,而不是简单地在DI容器中注册
    InstancesControlRepository
    ,并让它处理初始化类型?您是说在ClientFactory中?
    public partial class TeamspeakInstanceQueryClient : ITeamspeakInstanceQueryClient
    {
        private IInstanceControlRepository _instanceControlRepository;
    
        private const short MAX_RETRYS = 3;
        private const short TIME_TO_RETRY = 10;
    
        private EventHandler OnConnected;
    
        public Instance Instance { get; internal set; }
        public TeamSpeakClient Client { get; internal set; }
        public bool IsSelected { get; internal set; }
        private short _connectionTrys = 0;
    
        public TeamspeakInstanceQueryClient(IServiceProvider serviceProvider)
        {
            _instanceControlRepository = new InstancesControlRepository(ActivatorUtilities.CreateInstance<ApplicationDbContext>(serviceProvider));
            Init();
        }
    }
    
    public class InstancesControlRepository : IInstanceControlRepository
    {
        private readonly ApplicationDbContext _applicationDbContext;
    
        public InstancesControlRepository(ApplicationDbContext applicationDbContext)
        {
            _applicationDbContext = applicationDbContext;
        }
    }
    
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(option =>
            option.UseMySql(
                Configuration.GetConnectionString("DefaultConnection"),
                mySqlOptions => mySqlOptions.ServerVersion(new System.Version(10, 4, 13), ServerType.MariaDb)
            )
        );
        services.AddScoped<IInstanceControlRepository, InstancesControlRepository>();
        services.AddScoped<IServerQueryRepository, ServerQueryRepository>();
    
    class ClientFactory
    {
        private IServiceProvider _sp { get; set; }        
        private IServiceScope _scope  { get; set; }
        public  MyClass(IServiceProvider sp)
        {
            _sp = sp;
            _scope = sp.CreateScope();
        }
        public TeamspeakInstanceQueryClient Create() => new TeamspeakInstanceQueryClient(_scope.ServiceProvider);
    }
    
    // register it as singleton 
    services.AddSingleton<ClientFactory>();
    
    var factory = serviceProvider.GetRequiredService<ClientFactory>();
    queryClient = factory.Create();