【问题标题】:Dynamic retry proxy动态重试代理
【发布时间】:2012-05-08 00:52:26
【问题描述】:

考虑以下,它有效:

public interface IService
{
    void DoSomething(object arg);
    void DoSomethingElse(object arg, bool anotherArg);
    bool AndDoYetMoreStuff(object arg, object[] moreArgs);
}

public class Service : IService
{
    public void DoSomething(object arg){}

    public void DoSomethingElse(object arg, bool anotherArg){}

    public bool AndDoYetMoreStuff(object arg, object[] moreArgs)
    {
        return true;
    }
}

public class ServiceRetryProxy : IService
{
    const int retryLimit = 3;
    private readonly IService _service;

    public ServiceRetryProxy(IService service)
    {
        _service = service;
    }

    private void RetryOnException(Action<IService> ctx)
    {
        ReconnectOnException(service =>
        {
            ctx(service);
            return new object();
        });
    }

    private T RetryOnException<T>(Func<IService, T> ctx)
    {
        var counter = 0;
        Exception lastException = null;
        while (counter < retryLimit)
        {
            try
            {
                return ctx(_service);
            }
            catch (Exception ex)
            {
                lastException = ex;
                counter++;
            }
        }

        throw lastException;
    }

    public void DoSomething(object arg)
    {
        ReconnectOnException(x => x.DoSomething(arg));
    }

    public void DoSomethingElse(object arg, bool anotherArg)
    {
        ReconnectOnException(x => x.DoSomethingElse(arg, anotherArg));
    }

    public bool AndDoYetMoreStuff(object arg, object[] moreArgs)
    {
        return ReconnectOnException(x => x.AndDoYetMoreStuff(arg, moreArgs));
    }
}

这样做的问题是我必须为接口的每个方法编写一个代理方法。我想要一个更“动态”的解决方案,以便我可以将 RetryOnException(或任何其他逻辑)应用于任何给定接口上的每个方法。我目前正在研究 Castle DynamicProxy,但如果有其他选项呢?

【问题讨论】:

    标签: c# .net castle-dynamicproxy dynamic-proxy


    【解决方案1】:

    城堡动态代理当然是一种选择。

    但我个人会选择 postsharp: http://www.sharpcrafters.com/

    我已经将它用于类似的场景。我创建了 RetryOneexceptionAspect,您可以在其中指定异常类型、重试次数并将其应用于任何方法:

    [Serializable]
    public class RetryOnExceptionAspect : MethodInterceptionAspect
    {
        private readonly int maxRetries;
    
        private readonly Type exceptionType;
    
        public RetryOnExceptionAspect(int maxRetries, Type exceptionType)
        {
            this.maxRetries = maxRetries;
            this.exceptionType = exceptionType;
        }
    
        public override void OnInvoke(MethodInterceptionArgs args)
        {
            for (int i = 0; i < maxRetries + 1; i++)
            {
                try
                {
                    args.Proceed();
                }
                catch (Exception e)
                {
                    if (e.GetType() == exceptionType && i < maxRetries)
                    {
                        continue;
                    }
    
                    throw;
                }
    
                break;
            }
        }
    }
    

    用法如下:

    public class Service : IService
    {
        [RetryOnExceptionAspect(5, typeof(TimeoutException)]
        public void DoSomething()
        {
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多