如何使用依赖注入 (DI) 调用 class

How to call class with dependency injection (DI)

描述

我想用依赖注入创建一个 class 的对象。如果我手动设置参数,我会得到异常 Cannot access a disposed of the object..

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

在中间件中调用异步:

public async Task InvokeAsync(HttpContext context,
    IConfiguration configuration,
    IInstanceControlRepository instanceControlRepository,
    IServiceProvider serviceProvider)
{
    _configuration = configuration;
    _instanceControlRepository = instanceControlRepository;

    long timestamp = new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds();
    var instances = _instanceControlRepository.GetAllInstances();

    if (_time + 3 <= timestamp)
    {
        _time = timestamp;

        // Remove
        foreach(var client in TeamspeakInstanceQueryClients.ToList())
        {
            var cl = instances.ToList().Find(el => el.Id == client.Instance.Id);
            
            if(cl == null)
            {
                client.Dispose();
                TeamspeakInstanceQueryClients.RemoveAll(el => el.Instance.Equals(client.Instance));
            }
        }   

        // Create & Update
        foreach (var instance in instances)
        {
            var queryClient = TeamspeakInstanceQueryClients.Find(el => el.Instance.Id == instance.Id);

            if(queryClient == null)
            {
                //var test = ActivatorUtilities.CreateInstance<ApplicationDbContext>(serviceProvider);
                //var dbContext = serviceProvider.GetService<ApplicationDbContext>();
                //queryClient = new TeamspeakInstanceQueryClient(new InstancesControlRepository(ActivatorUtilities.CreateInstance<ApplicationDbContext>(serviceProvider)));
                queryClient = new TeamspeakInstanceQueryClient(serviceProvider);
                _ = queryClient.Connect(instance);
                TeamspeakInstanceQueryClients.Add(queryClient);
            }
            else
            {
                _ = queryClient.CheckInstanceData(instance);
            }
        }
    }

    await _next(context);
}

TeamspeakInstanceQueryClient.cs

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();
    }
}

InstancesControlRepository.cs

public class InstancesControlRepository : IInstanceControlRepository
{
    private readonly ApplicationDbContext _applicationDbContext;

    public InstancesControlRepository(ApplicationDbContext applicationDbContext)
    {
        _applicationDbContext = applicationDbContext;
    }
}

Startup.cs

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>();

我试过的

  1. 我试图通过服务提供商创建 class,但出现了同样的错误
  2. 我尝试在创建的 class 中使用服务提供商创建缺少的参数。但我需要注入服务提供商,它也会创建异常 Cannot access a disposed of the object. Object name: 'IServiceProvider'.
  3. 我试图让服务提供者静态化,所以它不能被处理,但它被处理了。

IServiceProvider 的实例似乎是 a scoped one 并且它在范围结束时被处理(我假设在请求结束时)。您可以尝试为 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>();

并在InvokeAsync中使用它:

var factory = serviceProvider.GetRequiredService<ClientFactory>();
queryClient = factory.Create();

P.S。此代码可以大大改进,仅用于演示目的。