对于我的一个DAL模块,我有很多重复的管道形状:
while (retry)
{
...
try
{
...do something
retry = false;
}
catch (SqlException sqlEx)
{
// Retry only if -2 = Connection Time Out or 1205 = Deadlock
if (sqlEx.Number == -2 || sqlEx.Number == 1205)
{
..retry if attempt < max
}
..log and rethrow exception
}
}
最近发现了PostSharp我试图用属性替换这些管道代码。
我最初的计划是: - 扩展OnMethodInvocationAspect并记住方法调用期间的方法调用事件args - 实现IOnExceptionAspect并实现OnException以检查异常类型,如果需要重试,则使用原始调用中的方法调用事件args对象,即:
[Serializable]
public sealed class RetryAttribute : OnMethodInvocationAspect, IOnExceptionAspect
{
[NonSerialized]
private MethodInvocationEventArgs m_initialInvocationEventArgs = null;
public override void OnInvocation(MethodInvocationEventArgs eventArgs)
{
if (m_initialInvocationEventArgs == null)
m_initialInvocationEventArgs = eventArgs;
base.OnInvocation(eventArgs);
}
public void OnException(MethodExecutionEventArgs eventArgs)
{
// check if retry is necessary
m_initialInvocationEventArgs.Proceed();
}
}
但是一旦我添加了IOnExceptionAspect,就不再触发OnInvocation方法..
有谁知道我需要在这做什么?或许我应该使用更合适的方面?
谢谢,
答案 0 :(得分:4)
您不能拥有实现两个方面接口的方面(在您的情况下为IOnMethodInvocation和IOnExceptionAspect)。编织者将采用一个任意接口并实现该方面。
我认为实现目标所需要的只是OnMethodInvocationAspect。为什么不在OnInvocation处理程序中放置for循环和try-catch?
-gael
答案 1 :(得分:1)
一个相当古老的问题,但我想分享一种可能有所帮助的方法。我们也成功地使用了这个范例。看看下面的代码。你所做的实际上是从MethodLevelAspect
继承并使用“建议”。
OnException
无法帮助args.Proceed()
抛出错误。因此,我们在OnInvoke
中直接使用了一个额外的try-catch块。
[Serializable]
public class MyAspectAttribute : MethodLevelAspect
{
object exceptionReturn = null;
public MyAspectAttribute(object ExceptionReturn) : base()
{
}
[OnMethodInvokeAdvice, SelfPointcut]
[AdviceDependency(AspectDependencyAction.Order, AspectDependencyPosition.Before, "OnEntry")]
public void OnInvoke(MethodInterceptionArgs args)
{
try
{
args.Proceed();
}
catch (Exception exc)
{
// do logging here
args.ReturnValue = exceptionReturn;
}
}
[OnMethodExceptionAdvice, SelfPointcut]
public void OnException(MethodExecutionArgs args)
{
}
[OnMethodEntryAdvice, SelfPointcut]
public void OnEntry(MethodExecutionArgs args)
{
}
[OnMethodExitAdvice, SelfPointcut]
[AdviceDependency(AspectDependencyAction.Order, AspectDependencyPosition.After, "OnInvoke")]
[AdviceDependency(AspectDependencyAction.Order, AspectDependencyPosition.After, "OnEntry")]
public void OnExit(MethodExecutionArgs args)
{
// your exit statements, such as committing transaction etc.
}
}
答案 2 :(得分:0)
这是一个相当简单的解决方案,不涉及PostSharp。创建以下实用程序方法。
public static void Try(Func<bool> task, int retryCount)
{
int attemptNum = 1;
while (attemptNum++ <= retryCount && task()) ;
}
然后创建您想要重试的任务。返回值应指示是否应尝试重试。
public bool UnreliableTask()
{
try
{
// Do something
}
catch (SqlException ex)
{
return (ex.Number == -2 || ex.Number == 1205);
}
return false;
}
然后只需调用这样的任务五次重试:
Try(UnreliableTask, 5);