[英]Polly with IDistributedCache and IHttpClientFactory Policy
Using the following code compiles fine, but receives the runtime error below.使用以下代码可以正常编译,但会收到下面的运行时错误。 Seems to be a conflict between the policy only supporting
HttpResponseMessage
when using IHttpClientFactory
?似乎是使用
IHttpClientFactory
时仅支持HttpResponseMessage
的策略之间的冲突?
The end goal is to be able to use several policies like retry, timeout, etc. and if everything is OK cache the result with the cache policy...最终目标是能够使用多种策略,如重试、超时等,如果一切正常,则使用缓存策略缓存结果......
Unable to cast object of type 'Polly.Caching.AsyncCachePolicy'1[System.String]' to type 'Polly.IAsyncPolicy'1[System.Net.Http.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");
}
As the error says you can not convert AsyncCachePolicy<string>
to IAsyncPolicy<HttpResponseMessage>
.正如错误所说,您无法将
AsyncCachePolicy<string>
转换为IAsyncPolicy<HttpResponseMessage>
。 Since all AsyncXYZPolicy
implements the IAsyncPolicy
interface that's why the problem is not coming from here.由于所有
AsyncXYZPolicy
都实现了IAsyncPolicy
接口,这就是问题不是来自这里的原因。 Rather than from the type parameter.而不是来自类型参数。
The AddHttpClient
returns an IHttpClientBuilder
. AddHttpClient
返回一个IHttpClientBuilder
。 There are several extension methods on them like AddPolicyHandlerFromRegistry
, AddTransientHttpErrorPolicy
or AddPolicyHandler
.它们上有几种扩展方法,例如
AddPolicyHandlerFromRegistry
、 AddTransientHttpErrorPolicy
或AddPolicyHandler
。 In all cases you need to register a policy where the return type is HttpResponseMessage
.在所有情况下,您都需要注册一个返回类型为
HttpResponseMessage
的策略。
If you would try to register your cache policy directly via the AddPolicyHandler
then it would cause compilation error rather than run-time error.如果您尝试直接通过
AddPolicyHandler
注册缓存策略,那么它会导致编译错误而不是运行时错误。 But because you retrieve the policy dynamically from the registry that's why it throws exception at runtime.但是因为您从注册表中动态检索策略,这就是它在运行时引发异常的原因。
Rather than defining a policy as AsyncCachePolicy<string>
you should define it as AsyncCachePolicy<HttpResponseMessage>
.与其将策略定义为
AsyncCachePolicy<string>
,不如将其定义为AsyncCachePolicy<HttpResponseMessage>
。 To do that you need to change the type parameter of the AsAsyncCacheProvider
method.为此,您需要更改
AsAsyncCacheProvider
方法的类型参数。
var cacheProvider = ServiceProvider
.GetRequiredService<IDistributedCache>()
.AsAsyncCacheProvider<HttpResponseMessage>();
You also need to change the cachePolicy
's type您还需要更改
cachePolicy
的类型
AsyncCachePolicy<HttpResponseMessage> cachePolicy =
Policy.CacheAsync(
cacheProvider: cacheProvider,
TimeSpan.FromSeconds(30));
Side note: I would also suggest to store the policy registry key ( "CachingPolicy"
) in a constant and refer to it when you register that and when you retrieve that.旁注:我还建议将策略注册表项(
"CachingPolicy"
)存储在一个常量中,并在注册和检索它时引用它。
UPDATE #1 :更新#1 :
I'm not even sure that you have to call the AsAsyncCacheProvider
method at all.我什至不确定您是否必须调用
AsAsyncCacheProvider
方法。 Let me double check.让我仔细检查一下。
UPDATE #2更新#2
After reading the source code of the AsAsyncCacheProvider
I've realized that it only supports byte[]
or string
as a type parameter.在阅读了
AsAsyncCacheProvider
的源代码后,我意识到它只支持byte[]
或string
作为类型参数。 This indicates that you can't use the AddPolicyHandler
methods here to automatically cache the response.这表明你不能在这里使用
AddPolicyHandler
方法来自动缓存响应。
Rather you have to use the AsyncPolicyCache<string>
directly in your MyClient
implementation.相反,您必须在
MyClient
实现中直接使用AsyncPolicyCache<string>
。 You need to modify the constructor of the MyClient
to recieve an IReadonlyPolicyRegister<string>
parameter as well.您还需要修改
MyClient
的构造函数以接收IReadonlyPolicyRegister<string>
参数。
private readonly IAsyncPolicy<string> _cachePolicy;
public MyClient(HttpClient client, IReadOnlyPolicyRegistry<string> policyRegistry)
{
_cachePolicy = policyRegistry.Get<IAsyncPolicy<string>>("CachingPolicy");
// ...
}
And inside your exposed method you need to explicitly use ExecuteAsync
在您公开的方法中,您需要显式使用
ExecuteAsync
await _cachePolicy.ExecuteAsync(context => getXYZ(), new Context("XYZUniqueKey"));
The getXYZ
needs to return a string (potentially the response body). getXYZ
需要返回一个字符串(可能是响应正文)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.