我有一个c#客户端实现System.ServiceModel.ClientBase<TChannel>
与SOAP API通信。
我希望客户端在超时时自动重试请求。
我想我可以使用像Polly这样的库来创建一个具有重试策略的HttpClient实例。
然而,我不知道如何用HttpClient实例化WCF客户端。
我也不确定我是否打算使用完全不同的方法,比如创建一个IEndpointBehavior
。
看起来有一个CreateChannel
实例方法可以被覆盖和一个ConfigureEndpoint
静态部分方法可以实现,但我找不到如何正确使用它们的任何例子来实现重试使用实例化的HttpClient或通过一些其他机制。
我已经通过文档搜索了构建客户端。有关于使用通道工厂的章节,但它似乎也没有提供HttpClient的机制。
关于预期异常的文档特别提到了TimeoutException
,但示例只是在客户端上尝试/捕获调用。
我真的不想做RetryOnTimeout(client => client.MethodToRetryOnTimeout());
。我知道我可以做到这一点,而且我知道我可以创建一个装饰器,用类似的逻辑包装所有客户机调用。我只是不认为这是正确的方法。
如果你能给我指出正确的方向,我将不胜感激。
在HttpClient
的情况下,AddPolicyHandler
注册一个PolicyHttpMessageHandler
,这是一个DelegatingHandler
。它基本上覆盖了SendAsync
:
Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken);
我没有使用WCF一段时间,但如果我的记忆服务良好,那么最接近这是客户端消息拦截器(IClientMessageInterceptor
)。尽管这是可行的,但不幸的是它并不那么容易实现。
另一种选择是使用RealProxy
。基本上,这里你可以覆盖Invoke
方法,并使用触发TimeoutException
和CommunicationException
的策略来修饰MethodBase
的Invoke
调用。这种方法的问题是RealProxy
在。net Core(或其后续版本)中不可用。
所以,唯一的选择是自己包装方法调用。
- 使用通用静态方法(在您的示例中是
RetryOnTimeout
) - 或创建自定义
ClientBase
派生类
class ResilientSampleClient: ClientBase<ISampleClient>, ISampleClient
{
private readonly IRetryPolicy retryPolicy = Policy
.Handle<TimeoutException>()
.Or<CommunicationException>)()
.WaitAndRetry(3, _ => TimeSpan.FromSeconds(1));
public ResilientSampleClient(): base(binding, endpointAddress) {}
public void MethodToRetryOnTimeout()
=> retryPolicy.Execute(base.Channel.MethodToRetryOnTimeout);
}
UPDATE # 1
在RealProxy
上花了更多的时间之后,我偶然发现了这篇迁移文章。建议使用DispatchProxy
代替。
我还没有测试过这段代码,但是根据迁移文档,上面基于RealProxy
的解决方案可以这样重写:
public class WcfClientProxy<T> : DispatchProxy where T : class
{
private readonly IRetryPolicy retryPolicy = Policy
.Handle<TimeoutException>()
.Or<CommunicationException>)()
.WaitAndRetry(3, _ => TimeSpan.FromSeconds(1));
private readonly WcfChannelFactory<T> _channelFactory;
public WcfClientProxy(WcfChannelFactory<T> channelFactory) : base()
{
this._channelFactory = channelFactory;
}
public override object Invoke(MethodInfo targetMethod, object[] args)
{
return retryPolicy.Execute(() => targetMethod.Invoke(this._channelFactory.CreateBaseChannel(), args));
}
}
您可以参考此文档了解实例wcf客户机。它将详细介绍创建客户端的细节。
使用polly Library创建http客户端,请参阅本文,本文详细介绍了在c#中创建实例的细节,并列出了创建客户端的步骤,以查看它是否对您有所帮助。