代码之家  ›  专栏  ›  技术社区  ›  Alexey Merson

如何为多个WCF客户端创建Polly策略

  •  2
  • Alexey Merson  · 技术社区  · 7 年前

    我需要与第三方服务集成。它有3个端点用于3个调用。就是这样,每个API调用都有自己的端点和自己的wsdl。因此,不同调用的POCO之间没有任何连接(如继承)。但这些电话的结果非常相似。尤其是每个结果都有“Errors”属性,该属性在管道分隔的字符串中包含错误。一些错误在调用之间共享(具有相同的名称),必须以类似的方式进行处理。

    我的目标是在引发异常或错误中存在名为“exception”的错误时重试调用。我正试图利用Polly来达到这个目标。我现在看到的唯一方法是为每个调用创建单独的策略。有没有办法为所有呼叫创建一个策略?

    示例代码如下(在实际项目中,导入wsdl时,VisualStudio自动生成*结果类和*服务接口):

    public partial class CreateResult
    {
        public string Errors {get;set;} 
    }
    
    public interface ICreateService
    {
        Task<CreateResult> CreateAsync();
    }
    
    public partial class UpdateResult
    {
        public string Errors {get;set;} 
    }
    
    public interface IUpdateService
    {
        Task<UpdateResult> UpdateAsync();
    }
    
    public partial class DeleteResult
    {
        public string Errors {get;set;} 
    }
    
    public interface IDeleteService
    {
        Task<DeleteResult> DeleteAsync();
    }
    
    public class Connector
    {
        private readonly ICreateService _createService;
        private readonly IUpdateService _updateService;
        private readonly IDeleteService _deleteService;
        private readonly Policy _policy = ???; 
    
        public Connector(ICreateService createService, IUpdateService updateService, IDeleteService deleteService)
        {
            _createService = createService;
            _updateService = updateService;
            _deleteService = deleteService;
        }
    
        public async Task<CreateResult> CreateAsync()
        {
            // sample policy: var policy = Policy.Handle<Exception>()
            //                                   .OrResult<CreateResult>(r => r.Errors.Contains("EXCEPTION"))
            //                                   .Retry();
            // Now I need to create such a policy for every call. How can I create a single policy or a factory method to enforce DRY principle?
    
            return _policy.ExecuteAsync(() => _createService.CreateAsync());
        }
    
        public async Task<UpdateAsync> UpdateAsync()
        {
            return _policy.ExecuteAsync(() => _updateService.UpdateAsync());
        }
    
        public async Task<DeleteResult> DeleteAsync()
        {
            return _policy.ExecuteAsync(() => _deleteService.DeleteAsync());
        }
    }
    
    1 回复  |  直到 7 年前
        1
  •  2
  •   Scott Hannen    7 年前

    假设每个返回类型都有一个包含 Error 对象通过让每个策略重用检查该集合的方法,可以消除一些代码重复。

    例如:

    public static class PolicyExtensions
    {
        public static bool ContainsExceptionMessage(this IEnumerable<Error> errors)
        {
            return errors.Any(error => error.Name.Contains("EXCEPTION"));
        }
    }
    

    您需要多个策略,但每个策略都可以重用此方法:

    var policy = Policy.HandleResult<MyResultClass>(
        result => result.Errors.ContainsExceptionMessage())
            .Or<Exception>()
            .Retry();
    

    如果每个类都实现了一个接口,指示其包含错误集合,则还可以创建一个泛型函数来返回策略:

    public interface IHasErrors
    {
        List<Error> Errors { get; }
    }
    
    Policy<THasErrors> CreateExceptionPolicy<THasErrors>() where THasErrors:IHasErrors
    {
        return Policy.HandleResult<THasErrors>(
                result => result.Errors.ContainsExceptionMessage())
            .Or<Exception>()
            .Retry();
    }
    

    现在您仍在创建多个策略,但它们更容易创建,而且它们的代码都不重复。

    var policy = CreateExceptionPolicy<UpdateResult>();