2009-08-21 30 views
1

方法對於我DAL模塊一個我有很多重複的管道的形狀:使用PostSharp重試對異常

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和方法調用 時記得方法調用事件參數 - 實施IOnExceptionAspect和實施onException的檢查異常類型,如果需要重試使用方法調用事件參數從原來的對象調用,即:

[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(); 
    } 
} 

但OnInvocation方法不解僱了,一旦我已經添加IOnExceptionAspect ..

有誰知道我需要在這裏做什麼?或者也許有更適合我應該使用的方面?

感謝,

+1

我要問的是,爲什麼你獲得這些例外(逾時死鎖),並重新設計了應用程式移除要求捕獲這些問題 - 在應用程序拋出另一種技術是不會提高設計\ implmentation – AwkwardCoder 2009-08-21 13:45:16

+0

嗯,是的,通常你不應該有死鎖。 重試的典型用法是在樂觀併發事務中工作。所以你可以重試,但我會同意奧利在那一點上。 – 2009-08-21 14:24:54

+0

超時和死鎖不會在我們的環境中經常發生,但是由於我們有很多不同的應用程序(全球有成千上萬的用戶使用了超過100個應用程序..)使用相同的數據庫,並且許多應用程序同時觸擊相同的表,過去我們遇到了僵局/超時的情況。 – theburningmonk 2009-08-21 14:28:51

回答

4

你不能有一個方面實現(在你的情況IOnMethodInvocation和IOnExceptionAspect)兩方面的接口。織布工將採取一個任意界面並且實施這個方面。

我認爲所有你需要實現你的目標是OnMethodInvocationAspect。爲什麼不把for循環和try-catch放在OnInvocation處理程序中?

-gael

+0

謝謝蓋爾,好主意,試了一下,並努力工作:) – theburningmonk 2009-08-21 14:29:42

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); 
+0

解決方案的問題是,你必須改變任何不可靠任務的代碼。可以有很多。如果使用PostSharp,則可以使用widl卡或Linq over Reflection來選擇應用的方法。也就是說,如果只有一對不可靠的方法,我寧願你的方法 - 函數式編程。 – 2009-08-23 06:09:19

+0

好點。然後,可以稍微修改Try方法,以便不要求任務通過布爾返回值報告成功/失敗,而只是將任何未處理的異常解釋爲失敗,否則就是成功。這將消除修改不可靠任務的需要。但是,當然,您仍然需要修改對該方法的任何調用以使用Try方法。 – 2009-08-23 15:10:47

1

一個相當古老的問題,但我想和大家分享的方法可能會有所幫助。我們也成功地使用了這個範例。看看下面的代碼。你所做的實際上是從MethodLevelAspect繼承並使用「Advices」。

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. 
    } 
}