Entity Framework Core bet 可以设置为使用备用连接字符串吗?
Can Entity Framework Core bet setup to use a backup connection string?
我公司使用 2 台 Windows 服务器。 1 服务器 运行 作为备份服务器,而不是 SQL 复制,备份服务器需要手动干预才能将其 运行 作为主服务器。我无法控制它,但我可以控制服务器上的 apps/services 运行。
我所做的是让所有服务都成为 运行 并添加 Rabbit MQ 作为集群消息代理以在服务器之间分配工作。这一切都很好,当我关闭服务器时,没有任何影响。
无论如何,就问题而言,我看到的唯一问题是这些服务使用相同的 SQL 服务器,而且我没有任何措施可以在主服务器出现故障时自动切换服务器。
所以我的问题是,有没有办法让 Entity Framework 在失败时使用替代连接字符串?
我正在使用带有 autofac 的模块方法作为我的服务的依赖注入。这是数据库注册。
public class AppsDbModule : Module
{
protected override void Load(ContainerBuilder builder)
{
RegisterContext<AppsDbContext>(builder);
}
private void RegisterContext<TContext>(ContainerBuilder builder) where TContext : DbContext
{
builder.Register(componentContext =>
{
var serviceProvider = componentContext.Resolve<IServiceProvider>();
var configuration = componentContext.Resolve<IConfiguration>();
var dbContextOptions = new DbContextOptions<TContext>(new Dictionary<Type, IDbContextOptionsExtension>());
var optionsBuilder = new DbContextOptionsBuilder<TContext>(dbContextOptions)
.UseApplicationServiceProvider(serviceProvider)
.UseSqlServer(configuration.GetConnectionString("AppsConnection"),
serverOptions => serverOptions.EnableRetryOnFailure(5, TimeSpan.FromSeconds(30), null));
return optionsBuilder.Options;
}).As<DbContextOptions<TContext>>()
.InstancePerLifetimeScope();
builder.Register(context => context.Resolve<DbContextOptions<TContext>>())
.As<DbContextOptions>()
.InstancePerLifetimeScope();
builder.RegisterType<TContext>()
.AsSelf()
.InstancePerLifetimeScope();
}
}
和我的appsettings.json
这样
"ConnectionStrings": {
"AppsConnection": "Data Source=primary;Initial Catalog=Apps;User Id=me;Password=topsecret"
}
除了你完全控制创建数据库连接的帖子外,在网上找不到任何东西,但我是通过 DI 提供连接的。
使用 .Net 5 并且应用程序是辅助服务。
您可以在实现接口 IExecutionStrategy
时定义自定义重试策略。
如果你想重用默认的 SQL 服务器重试策略,你可以从 SqlServerRetryingExecutionStrategy
派生重写方法 ShouldRetryOn
:
public class SqlServerSwitchRetryingExecutionStrategy : SqlServerRetryingExecutionStrategy
{
public string _switchConnectionString;
public SqlServerSwitchRetryingExecutionStrategy(ExecutionStrategyDependencies dependencies, string switchConnectionString)
: base(dependencies, 3)
{
_switchConnectionString = switchConnectionString;
}
protected override bool ShouldRetryOn(Exception exception)
{
if (exception is SqlException sqlException)
{
foreach (SqlError err in sqlException.Errors)
{
switch (err.Number)
{
// For this type of error, switch the connection string and retry
case 1418: // The server can't be reached or does not exist
case 4060: // Cannot open database
case 4064: // Cannot open user default database database
var db = Dependencies.CurrentContext.Context.Database;
var current = db.GetConnectionString();
if(current != _switchConnectionString)
db.SetConnectionString(_switchConnectionString);
return true;
}
}
}
return base.ShouldRetryOn(exception);
}
}
I am not sure which errors to catch for your scenario.
You should test and find the errors to handle.
The full list is available Database engine errors.
注入策略:
new DbContextOptionsBuilder<TContext>(dbContextOptions)
.UseSqlServer(
configuration.GetConnectionString("AppsConnection"),
serverOptions => serverOptions.ExecutionStrategy(dependencies =>
new SqlServerSwitchRetryingExecutionStrategy(
dependencies,
configuration.GetConnectionString("AppsConnectionBackup"))
)
);
如果你想要一个完整的自定义策略,你可以从SqlServerRetryingExecutionStrategy中获得灵感。
我公司使用 2 台 Windows 服务器。 1 服务器 运行 作为备份服务器,而不是 SQL 复制,备份服务器需要手动干预才能将其 运行 作为主服务器。我无法控制它,但我可以控制服务器上的 apps/services 运行。
我所做的是让所有服务都成为 运行 并添加 Rabbit MQ 作为集群消息代理以在服务器之间分配工作。这一切都很好,当我关闭服务器时,没有任何影响。
无论如何,就问题而言,我看到的唯一问题是这些服务使用相同的 SQL 服务器,而且我没有任何措施可以在主服务器出现故障时自动切换服务器。
所以我的问题是,有没有办法让 Entity Framework 在失败时使用替代连接字符串?
我正在使用带有 autofac 的模块方法作为我的服务的依赖注入。这是数据库注册。
public class AppsDbModule : Module
{
protected override void Load(ContainerBuilder builder)
{
RegisterContext<AppsDbContext>(builder);
}
private void RegisterContext<TContext>(ContainerBuilder builder) where TContext : DbContext
{
builder.Register(componentContext =>
{
var serviceProvider = componentContext.Resolve<IServiceProvider>();
var configuration = componentContext.Resolve<IConfiguration>();
var dbContextOptions = new DbContextOptions<TContext>(new Dictionary<Type, IDbContextOptionsExtension>());
var optionsBuilder = new DbContextOptionsBuilder<TContext>(dbContextOptions)
.UseApplicationServiceProvider(serviceProvider)
.UseSqlServer(configuration.GetConnectionString("AppsConnection"),
serverOptions => serverOptions.EnableRetryOnFailure(5, TimeSpan.FromSeconds(30), null));
return optionsBuilder.Options;
}).As<DbContextOptions<TContext>>()
.InstancePerLifetimeScope();
builder.Register(context => context.Resolve<DbContextOptions<TContext>>())
.As<DbContextOptions>()
.InstancePerLifetimeScope();
builder.RegisterType<TContext>()
.AsSelf()
.InstancePerLifetimeScope();
}
}
和我的appsettings.json
这样
"ConnectionStrings": {
"AppsConnection": "Data Source=primary;Initial Catalog=Apps;User Id=me;Password=topsecret"
}
除了你完全控制创建数据库连接的帖子外,在网上找不到任何东西,但我是通过 DI 提供连接的。
使用 .Net 5 并且应用程序是辅助服务。
您可以在实现接口 IExecutionStrategy
时定义自定义重试策略。
如果你想重用默认的 SQL 服务器重试策略,你可以从 SqlServerRetryingExecutionStrategy
派生重写方法 ShouldRetryOn
:
public class SqlServerSwitchRetryingExecutionStrategy : SqlServerRetryingExecutionStrategy
{
public string _switchConnectionString;
public SqlServerSwitchRetryingExecutionStrategy(ExecutionStrategyDependencies dependencies, string switchConnectionString)
: base(dependencies, 3)
{
_switchConnectionString = switchConnectionString;
}
protected override bool ShouldRetryOn(Exception exception)
{
if (exception is SqlException sqlException)
{
foreach (SqlError err in sqlException.Errors)
{
switch (err.Number)
{
// For this type of error, switch the connection string and retry
case 1418: // The server can't be reached or does not exist
case 4060: // Cannot open database
case 4064: // Cannot open user default database database
var db = Dependencies.CurrentContext.Context.Database;
var current = db.GetConnectionString();
if(current != _switchConnectionString)
db.SetConnectionString(_switchConnectionString);
return true;
}
}
}
return base.ShouldRetryOn(exception);
}
}
I am not sure which errors to catch for your scenario. You should test and find the errors to handle. The full list is available Database engine errors.
注入策略:
new DbContextOptionsBuilder<TContext>(dbContextOptions)
.UseSqlServer(
configuration.GetConnectionString("AppsConnection"),
serverOptions => serverOptions.ExecutionStrategy(dependencies =>
new SqlServerSwitchRetryingExecutionStrategy(
dependencies,
configuration.GetConnectionString("AppsConnectionBackup"))
)
);
如果你想要一个完整的自定义策略,你可以从SqlServerRetryingExecutionStrategy中获得灵感。