ASP.NET Core依赖项注入:在运行时传递参数

时间:2019-02-15 19:36:55

标签: c# asp.net-core dependency-injection asp.net-core-webapi

我在测试项目中使用ASP.NET核心依赖项注入 ,以设置测试所使用的文本上下文(因此,此处不能使用构造函数注入)。在ConfigureServices中,我注册了服务,效果很好:

  public void ConfigureServices(IServiceCollection services)
  {
      // Scans assemblies and adds MediatR handlers, preprocessors, and postprocessors implementations to the container.            
      services.AddMediatR(
       typeof(Application.Logic.Queries.FindUserByEmailAddressHandler));            
      services.AddTransient<ILocalDb, LocalDb>(l => new LocalDb(null));
      services.AddTransient<IUnitOfWork, UnitOfWork>(uow => new UnitOfWork(""));            
      services.AddTransient<IUserRepository, UserRepository>();
  }

但是,当尝试获取我的工作单元实例时,我遇到了问题:

   var localDb = serviceProvider.GetService<ILocalDb>();
   var unitOfWork = serviceProvider.GetService<IUnitOfWork>(); <- need to pass constructor parameter

您看到,UnitOfWork构造函数接受一个连接字符串,并且我必须传递来自localDb的此连接字符串(LocalDb会动态创建一个测试数据库)。

在StructureMap中,当获取实例时,我可以将参数传递给构造函数,如下所示:

  x.For<IUnitOfWork>().Use<UnitOfWork>().Ctor<string>().Is(localDb.ConnectionString); });

如何使用ASP.NET Core依赖项注入来做到这一点?

2 个答案:

答案 0 :(得分:0)

我找到了解决方法。

我在自己的文本上下文中执行每个测试,例如(简化示例):

  using (var context = IntegrationTestEnvironment.Setup())
  {
      User bobbyUserDo = new User();
      Profile bobbyPatientDo = new Patient(bobbyUserDo, "bobbyPatient@hotmail.com");
      var bobbyUserDb = await context.UserRepository.AddOrUpdateAsync(bobbyUserDo);
      bobbyUserDb.Should().NotBeNull();
      bobbyUserDb.Id.Should().BeGreaterThan(0);
      bobbyUserDb.Profiles.Should().HaveCount(1);
      bobbyUserDb.Profiles.First().Id.Should().BeGreaterThan(0);
  }

在设置方法中,我准备环境:

  public static IntegrationTestContext Setup(bool prefillWithTestData)
  {           
        var webHost = WebHost.CreateDefaultBuilder()                
            .UseStartup<Startup>()
            .Build();
        var serviceProvider = new DependencyResolverHelpercs(webHost);
  }

Startup方法包含ConfigureServices方法,在其中配置测试所需的所有服务:

  public void ConfigureServices(IServiceCollection services)
    {            
        // Scans assemblies and adds MediatR handlers, preprocessors, and postprocessors implementations to the container.            
        services.AddMediatR(typeof(Application.Logic.Queries.FindUserByEmailAddressHandler));

        var localDb = new LocalDb();
        services.AddSingleton<ILocalDb, LocalDb>(uow => localDb);
        services.AddSingleton<IUnitOfWork, UnitOfWork>(uow => new UnitOfWork(localDb.ConnectionString));
        services.AddSingleton<IUserRepository, UserRepository>();
    }

那时,我创建了一个LocalDb(它创建了一个本地数据库),然后我可以简单地将连接字符串传递给我的工作单元。

然后,该测试可以在我正确配置了依赖项注入且在该测试中有效的上下文中运行。这就是为什么我使用Singleton的原因:在特定测试的上下文中,实例是相同的;在测试之后,所有东西都被丢弃,本地数据库被删除。

答案 1 :(得分:0)

无需传递上述的UnitOfWork参数。使用这样的配置定义您的UnitOfWork结构

            var mySqlConn = Configuration.GetSection("MySqlConnection").Get<MySqlConnection>();
            services.AddDbContext<MySQLContext>(options => options.UseMySql(mySqlConn.MySqlConnectionString));

            services.AddScoped(typeof(IRepository<,>), typeof(Repository<,>));
            services.AddTransient(typeof(IUnitOfWork<>), typeof(UnitOfWork<>));

Visual Studio将在运行时对其进行解析