【问题标题】:How to use a Service or DbContext inside DbCommandInterceptor?如何在 DbCommandInterceptor 中使用 Service 或 DbContext?
【发布时间】:2020-03-09 23:41:36
【问题描述】:

我有一个将数据从 MySql 数据库同步到 SQL Server 数据库的应用程序。

考虑这两个 DbContext 服务:

services.AddDbContext<SqlServerContext>(options => options
    .UseSqlServer(Configuration.GetConnectionString("SqlServer")));

services.AddDbContext<MySqlContext>(options => options
    .UseMySql(Configuration.GetConnectionString("MySql"))
    .AddInterceptors(new MySqlInterceptor()));

MySqlInterceptor();我想注入/解析/使用Service 甚至SqlServerContext,以便获得修改CommandText 的配置。

有什么想法吗?

【问题讨论】:

    标签: c# ef-core-3.0


    【解决方案1】:

    正如@vasil 在他的answer 中提到的那样:

    根据您要覆盖的方法,您将收到 CommandEventData 方法定义中的对象 DbContext 作为属性。

    在我的例子中,我想解决一个使用另一个 DbContext 的服务,但事实证明这很麻烦;因此,我最终将所需的设置放入 appsettings.json,并使用IConfiguration 服务获取设置值并将其发送到拦截器构造函数:

    services.AddDbContext<MySqlContext>(options => options
        .UseMySql(Configuration.GetConnectionString("MySql"))
        .AddInterceptors(new MySqlInterceptor(Configuration["SettingValue"])));
    

    注意:如果您找到了这个答案,并且正在寻找一种方法来解决 ConfigureService 方法中的服务,而无需调用 BuildServiceProvider,就像 David Fowler 在 @987654323 上所说的那样@,你会是:

    在尝试构建容器的同时构建容器

    你最终会得到:

    2 个容器,其中一个永远不会被丢弃。

    您可以按照 Nkosi 在他的 answer 中的建议进行操作:

    services.AddScoped<IService>(x => 
        new Service(x.GetRequiredService<IOtherService>(),
                    x.GetRequiredService<IAnotherOne>(), 
                    ""));
    

    【讨论】:

      【解决方案2】:

      根据您要覆盖的方法,您将在方法定义中收到CommandEventData 对象,该对象具有DbContext 作为属性。

      关于服务和配置,您可以在注册前配置拦截器。
      而不是这个:

      services.AddDbContext<MySqlContext>(options => options
          .UseMySql(Configuration.GetConnectionString("MySql"))
          .AddInterceptors(new MySqlInterceptor()));
      

      你可以的

      var interceptor = new MySqlInterceptor(service1, service2 ... etc);
      services.AddDbContext<MySqlContext>(options => options
       .UseMySql(Configuration.GetConnectionString("MySql"))
       .AddInterceptors(interceptor))
      

      如何解析拦截器实例:
      如果您需要自动连接拦截器的依赖项,您可以执行以下操作

      services.AddTransient<Service1>();
      services.AddTransient<Service2>();
      services.AddTransient<MySqlInterceptor>();
      // resolve the instalce of the interceptor
      var serviceProvider = services.BuildServiceProvider();
      var interceptor = serviceProvider.GetService<MySqlInterceptor>();
      // configure mysql context and interceptor
      services.AddDbContext<MySqlContext>(options => options
       .UseMySql(Configuration.GetConnectionString("MySql"))
       .AddInterceptors(interceptor))
      

      【讨论】:

      • 请原谅我缺乏知识:有没有办法让MySqlInterceptor 的实例也注入 service1?喜欢MySqlInterceptor(IService1)
      • 抛出警告:Warning ASP0000 Calling 'BuildServiceProvider' from application code results in an additional copy of singleton services being created. Consider alternatives such as dependency injecting services as parameters to 'Configure'.
      • 这是一个小观察,但值得一提:第一个建议提供的不多,您可以随时.AddInterceptors(MySqlInterceptor(service1)))
      • 如果你仔细想想,ConfigureService 真的是用于容器设置的,所以在它里面创建一个具体的东西就达不到目的了。
      • @是的,我同意。当您有复杂的依赖关系图时(例如 Servcie1 依赖于其他服务......等),它很有用,因此您不必手动构建图。发表您的想法,我对您的解决方案感兴趣。
      猜你喜欢
      • 1970-01-01
      • 2017-11-05
      • 2021-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-01
      • 1970-01-01
      相关资源
      最近更新 更多