如何在 DbCommandInterceptor 中使用服务或 DbContext?

How to use a Service or DbContext inside DbCommandInterceptor?

我有一个应用程序可以将数据从 MySql 数据库同步到 SQL 服务器数据库。

考虑这两个 DbContext 服务:

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

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

MySqlInterceptor();我想inject/resolve/use一个Service甚至SqlServerContext,为了得到配置修改CommandText

有什么想法吗?

根据您要覆盖的方法,您将在方法定义中收到 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))

正如@vasil 在他的 中提到的:

Depending on the method you are going to override, you will receive CommandEventData object in the method definition which has the DbContext as property.

但就我而言,我想解析使用 另一个 DbContext 的服务,这被证明很麻烦;所以我最终将我需要的设置放入 appsettings.json,并使用 IConfiguration 服务获取设置值并将其发送到拦截器构造函数:

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

注意:如果您找到了这个答案,并且正在寻找一种方法来解决 ConfigureService 方法中的服务,而无需调用 BuildServiceProvider ,就像大卫·福勒 (David Fowler) 在 Github issue 上说的那样,您会:

building the container while trying to build it

你最终会得到:

2 containers and one of them will never be disposed.

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

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