【问题标题】:Polly with IDistributedCache and IHttpClientFactory Policy使用 IDistributedCache 和 IHttpClientFactory 策略进行 Polly
【发布时间】:2022-10-02 13:31:31
【问题描述】:

使用以下代码可以正常编译,但会收到下面的运行时错误。似乎是使用IHttpClientFactory时只支持HttpResponseMessage的策略之间的冲突?
最终目标是能够使用多种策略,如重试、超时等,如果一切正常,则使用缓存策略缓存结果......

无法转换类型的对象 \'Polly.Caching.AsyncCachePolicy\'1[System.String]\' 输入 \'Polly.IAsyncPolicy\'1[System.Net.Http.HttpResponseMessage]\'.\'

serviceCollection.AddStackExchangeRedisCache(options =>
{
    options.Configuration = \"...\";
});
IPolicyRegistry<string> registry = serviceCollection.AddPolicyRegistry();
var cacheProvider = ServiceProvider.GetRequiredService<IDistributedCache>().AsAsyncCacheProvider<string>();
serviceCollection.AddSingleton(serviceProvider => cacheProvider);

AsyncCachePolicy<string> cachePolicy =
Policy.CacheAsync(
    cacheProvider: cacheProvider,
    TimeSpan.FromSeconds(30));
registry.Add(\"CachingPolicy\", cachePolicy);

serviceCollection.AddHttpClient<IMyClient, MyClient>()
    .AddPolicyHandlerFromRegistry(this.PolicySelector)
    
private IAsyncPolicy<HttpResponseMessage> PolicySelector(IReadOnlyPolicyRegistry<string> policyRegistry, HttpRequestMessage httpRequestMessage)
{
    return policyRegistry.Get<IAsyncPolicy<HttpResponseMessage>>(\"CachingPolicy\");
}
  • 您将策略缓存为 AsyncCachePolicy<string> 类型,然后尝试将其解析为 AsyncCachePolicy<HttpResponseMessage> 类型。不确定您要达到什么目的,但这就是错误。

标签: c# caching .net-6.0 polly retry-logic


【解决方案1】:

正如错误所说,您无法将AsyncCachePolicy&lt;string&gt; 转换为IAsyncPolicy&lt;HttpResponseMessage&gt;。由于所有AsyncXYZPolicy 都实现了IAsyncPolicy 接口,这就是问题不是来自这里的原因。而不是来自类型参数。

AddHttpClient 返回一个 IHttpClientBuilder。它们上有several extension methods,例如AddPolicyHandlerFromRegistryAddTransientHttpErrorPolicyAddPolicyHandler。在所有情况下,您都需要注册一个返回类型为HttpResponseMessage 的策略。

如果您尝试直接通过AddPolicyHandler 注册您的缓存策略,那么它会导致编译错误而不是运行时错误。但是因为您从注册表中动态检索策略,这就是它在运行时引发异常的原因。

如何解决?

与其将策略定义为AsyncCachePolicy&lt;string&gt;,不如将​​其定义为AsyncCachePolicy&lt;HttpResponseMessage&gt;。为此,您需要更改 AsAsyncCacheProvider 方法的类型参数。

var cacheProvider = ServiceProvider
   .GetRequiredService<IDistributedCache>()
   .AsAsyncCacheProvider<HttpResponseMessage>();

您还需要更改cachePolicy 的类型

AsyncCachePolicy<HttpResponseMessage> cachePolicy =
Policy.CacheAsync(
    cacheProvider: cacheProvider,
    TimeSpan.FromSeconds(30));

旁注:我还建议将策略注册表项 ("CachingPolicy") 存储在一个常量中,并在注册和检索时引用它。


更新#1

我什至不确定您是否必须调用 AsAsyncCacheProvider 方法。让我仔细检查一下。


更新#2

在阅读了AsAsyncCacheProvider 的源代码后,我意识到它只支持byte[]string 作为类型参数。这表明您不能使用此处的AddPolicyHandler 方法来自动缓存响应。

相反,您必须直接在您的MyClient 实现中使用AsyncPolicyCache&lt;string&gt;。您还需要修改MyClient 的构造函数以接收IReadonlyPolicyRegister&lt;string&gt; 参数。

private readonly IAsyncPolicy<string> _cachePolicy;
public MyClient(HttpClient client, IReadOnlyPolicyRegistry<string> policyRegistry)
{
    _cachePolicy = policyRegistry.Get<IAsyncPolicy<string>>("CachingPolicy");
    // ...
}

在您公开的方法中,您需要明确使用ExecuteAsync

await _cachePolicy.ExecuteAsync(context => getXYZ(), new Context("XYZUniqueKey"));

getXYZ 需要返回一个字符串(可能是响应正文)。

【讨论】:

  • 我也得出了同样的结论。我决定不使用它,因为: 1. 它不像内存缓存提供程序和 IHttpClientFactory 那样无缝。我不想用这种愚蠢的语法来包装我所有的 http 调用。 2. 我什至无法让它与流响应和读取标题(例如分页等)一起使用,它们也是空的。我可能仍然使用其他策略。我将处理这个库之外的缓存。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-22
  • 1970-01-01
相关资源
最近更新 更多