如何将IConfiguration传入静态类配置Dapper扩展的Polly重试次数?
你想到的方案是.NET生态下处理这类需求的合理方案,也是更符合依赖注入最佳实践的实现方式。
原来把重试策略定义为静态属性的方式,本质上是硬编码了重试次数,很难和.NET的配置体系、依赖注入体系结合:静态属性的初始化时机远早于应用配置加载、依赖注入容器构建的流程,自然无法直接注入IConfiguration读取配置值。就算你用静态方法手动给静态属性赋值,也会存在初始化顺序不可控、无法单元测试、配置变更无法动态生效等问题。
你提到的「将Polly策略注册为单例、再传入扩展方法」的思路完全可行,落地可以按以下步骤做:
- 在应用启动时读取配置,构建策略并注册为单例,示例代码:
// Program.cs 中注册 builder.Services.AddSingleton<AsyncRetryPolicy>(sp => { var config = sp.GetRequiredService<IConfiguration>(); // 从配置读取重试次数,可设置默认兜底值 var retryTimes = config.GetValue<int>("Database:RetryCount", 3); var logger = sp.GetRequiredService<ILogger<AsyncRetryPolicy>>(); return Policy .Handle<SqlException>(SqlServerTransientExceptionDetector.ShouldRetryOn) .Or<TimeoutException>() .OrInner<Win32Exception>(SqlServerTransientExceptionDetector.ShouldRetryOn) .WaitAndRetryAsync(retryTimes, (exception, timeSpan, retryCount, context) => { logger.LogWarning( exception, "WARNING: Error talking to ReportingDb, will retry after {RetryTimeSpan}. Retry attempt {RetryCount}", timeSpan, retryCount ); }); });
- 修改现有Dapper扩展方法,增加
AsyncRetryPolicy作为入参即可,示例:
public static async Task<IEnumerable<T>> QueryWithRetryAsync<T>( this IDbConnection conn, AsyncRetryPolicy retryPolicy, string sql, object param = null, IDbTransaction transaction = null) { return await retryPolicy.ExecuteAsync(async () => await conn.QueryAsync<T>(sql, param, transaction)); }
- 业务使用时,只需从依赖注入容器中获取提前注册好的重试策略,传入扩展方法即可。如果不想每次调用都手动传策略,也可以进一步把Dapper相关操作封装到非静态的仓储服务中,在仓储服务的构造函数中注入重试策略,内部调用扩展方法时自动传入,调用方完全感知不到策略的存在,使用更简洁。
当然也有其他实现方式,比如给静态策略类增加初始化方法,启动时手动传入配置的重试次数,但这种方案无法利用依赖注入的生命周期管理能力,也不便于单元测试,优先级低于你想到的单例方案。
内容的提问来源于stack exchange,提问作者daxu
相关产品推荐
相关产品推荐

