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中获得灵感。