Ter*_*rje 10 c# logging dependency-injection polly asp.net-core-2.1
或者:如何从静态方法记录。
从https://github.com/App-vNext/Polly你可以看到像这样的例子,其中记录器神奇地可用:
Policy
.Timeout(30, onTimeout: (context, timespan, task) =>
{
logger.Warn($"{context.PolicyKey} at {context.ExecutionKey}: execution timed out after {timespan.TotalSeconds} seconds.");
});
Run Code Online (Sandbox Code Playgroud)
在我的代码中,我使用IHttpClientFactory
dotnet core 2.1 中的新模式,并将其添加到我的 Startup.csConfigureServices
方法中:
services.AddHttpClient<IMySuperHttpClient, MySuperHttpClient>()
.AddPolicyHandler(MySuperHttpClient.GetRetryPolicy())
.AddPolicyHandler(MySuperHttpClient.GetCircuitBreakerPolicy());
Run Code Online (Sandbox Code Playgroud)
静态且GetRetryPolicy
看起来像这样:
internal static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
.WaitAndRetryAsync(
retryCount: 4,
sleepDurationProvider: retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
onRetry: OnRetry);
}
Run Code Online (Sandbox Code Playgroud)
其中OnRetry
方法也必须是静态的:
private static void OnRetry(DelegateResult<HttpResponseMessage> delegateResult, TimeSpan timespan, Context context)
{
// var logger = ??
// logger.LogWarning($"API call failed blah blah.");
}
Run Code Online (Sandbox Code Playgroud)
ILoggerFactory
如果可能的话,如何访问这里?
正如山地旅行者的评论中所述,有多种方法可以解决该问题:
Context
之间传递任意对象Execute(Async)
onRetry(Async)
AddPolicyHandler
前一种解决方案需要显式调用Execute
/ExecuteAsync
才能提供Context
封装ILogger
实例的对象。对于命名/类型化 Http 客户端,此路由不是一个可行的选择,因为您HttpClient
用PolicyHttpMessageHandler
. Execute(Async)
因此,代表您调用 Handler 的不是您的代码。
后一个解决方案提供对 的访问,IServiceProvider
您可以从中检索任何已注册的服务。(它还将请求作为参数传递。)
services.AddHttpClient<IMySuperHttpClient, MySuperHttpClient>()
.AddPolicyHandler((provider, _) => MySuperHttpClient.GetRetryPolicy(provider))
Run Code Online (Sandbox Code Playgroud)
因此,您需要做的就是将其IServiceProvider
向下传递给您的 OnRetry
方法
internal static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy(IServiceProvider provider)
=> HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == HttpStatusCode.NotFound)
.WaitAndRetryAsync(4,
retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
OnRetry(provider));
}
Run Code Online (Sandbox Code Playgroud)
代表期望的WaitAndRetryAsync
地方不存在这种过载。我们需要引入一个像这样的辅助方法:onRetry
IServiceProvider
private static Action<DelegateResult<HttpResponseMessage>, TimeSpan> OnRetry(IServiceProvider provider)
=> (dr, ts) => OnRetry(dr, ts, provider);
private static void OnRetry(DelegateResult<HttpResponseMessage> delegateResult, TimeSpan timespan, IServiceProvider provider)
{
// var logger = ??
// logger.LogWarning($"API call failed blah blah.");
}
Run Code Online (Sandbox Code Playgroud)
OnRetry
接收IServiceProvider
并返回一个Action<DelegateResult<HttpResponseMessage>, TimeSpan>
WaitAndRetryAsync
委托onRetry
OnRetry
与你的相同,我刚刚将你的上下文参数替换为提供程序因此,基本上第一个充当和第二个OnRetry
之间的适配器以通过.WaitAndRetryAsync
OnRetry
provider