简体   繁体   English

使用 IDistributedCache 和 IHttpClientFactory 策略进行 Polly

[英]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 .它们上有几种扩展方法,例如AddPolicyHandlerFromRegistryAddTransientHttpErrorPolicyAddPolicyHandler 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.但是因为您从注册表中动态检索策略,这就是它在运行时引发异常的原因。

How to fix it?如何解决?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM