2013-03-04 5 views
10

私は例外を記録し、FaultExceptionsとしてそれらをスローするWCFサービスを持っています。デザインパターン/ C#コードの反復ビットのためのトリック

私は多くの繰り返しを行っています。各サービス方法で。

try { 
    // do some work 

} 
catch(Exception ex) 
{ 
    Logger.log(ex); 

    // actually will be Fault Exception but you get the idea. 
    throw ex; 
} 

私は、各サービスでtry/catchを切り貼りしているので、これを行うためのよりエレガントな方法を探しています。

これをよりエレガントにするために使用できるデザインパターン/ C#トリックがありますか?

+16

"スローex;"元のコールスタックを失いますが、 "throw;"ではない。 – Polyfun

+1

tryの本体も同じようにキャッチしますか? – christopher

+1

あなたは、ここでAspect Orientated Programmingをよく見ています - http://msdn.microsoft.com/en-us/library/aa288717%28v=vs.71%29.aspx。 PostSharpのような第三者ソリューションの多くは、これを正確に行う例外処理の側面を持っています。別の(悪い)解決策は、ローカルtryキャッチブロックを持つのではなく、アプリケーションレベル(たとえば、AppDomain_UnhandledExceptionなど)ですべての例外をキャッチすることです。私は実際にはローカルの例外処理にあなたを結びつけるか、try/catch(スロー)でコードを散らすので悪化します。 – dash

答えて

1

Template method patternこれだけで、C#の代理人(またはlambdas)を使用して継承なしで簡単に実装できます。

0

をスローすると、呼び出すスタックの上に例外例外が伝播するため、すべての深いレベルでそれを処理しないようにすることができます。 Exceptionオブジェクトにはスタックトレースも含まれています。

すべてのレベルでキャッチする必要がある場合は、throwを覚えておいてください。コールスタックは影響を受けず、代わりに使用されます。

0

global.asaxファイルのApplication_Errorイベントを購読しようとすることもできます。

デスクトップアプリケーションの場合はAppDomainUnhandledExceptionイベントがあります。

+0

@Downvoters:この解決策に何が間違っているのかご意見ください! – Carsten

2

WCF固有の場合、独自のErrorHandlerを追加することができます。これにより、メソッドが例外をスローするたびに実行される独自のコードを「挿入」することができます。

あなたはこのようにそれを設定することができます。また、あなたは、例外のすべての種類を投げることができますし、あなたのビジネス層を修正することなく、適切に、後にWCFによって処理される例外を、障害に変換

serviceHost.Description.Behaviors.Add(new ErrorHandlerBehavior()); //Add your own ErrorHandlerBehaviour 

public class ErrorHandlerBehavior : IErrorHandler, IServiceBehavior 
{ 
    private static readonly Logger log = LogManager.GetCurrentClassLogger(); 

    public bool HandleError(Exception error) 
    { 
     if (error is CommunicationException) 
     { 
      log.Info("Wcf has encountered communication exception."); 
     } 
     else 
     { 
      // Log 
     } 

     return true; 
    } 

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault) 
    { 
     //Here you can convert any exception to FaultException like this: 
     if (error is FaultException) 
      return; 

     var faultExc = new FaultException(error.Message); 
     var faultMessage = faultExc.CreateMessageFault(); 

     fault = Message.CreateMessage(version, faultMessage, faultExc.Action); 
    } 

    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, 
     BindingParameterCollection bindingParameters) 
    { 
    } 

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) 
    { 
     foreach (ChannelDispatcherBase channelDispatcher in serviceHostBase.ChannelDispatchers) 
     { 
      var channelDisp = channelDispatcher as ChannelDispatcher; 

      if (channelDisp != null) 
       channelDisp.ErrorHandlers.Add(this); 
     } 
    } 

    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) 
    { 
    } 
} 

このtry/catchコードを適用してそこに変換します。

5

私たちは、私はヘルパーデリゲートを使用することで解決しました私たちのWCFサービス、のいずれかで同様の問題を持っている:

public static void ErrorHandlingWrapper(Action DoWork) 
{ 
    try { 
     DoWork(); 
    } 
    catch(Exception ex) 
    { 
     Logger.log(ex); 

     // actually will be Fault Exception but you get the idea. 
     throw; 
    } 
} 

使用法:

public void MyMethod1() 
{ 
    ErrorHandlingWrapper(() => { 
     // do work 
    }); 
} 

public void MyMethod2() 
{ 
    ErrorHandlingWrapper(() => { 
     // do work 
    }); 
} 

をあなたはまだラッパーを繰り返す必要がしかし、それはずっと少ないコードであり、try..catchのロジックを1か所で変更することができます。

9

あなたはAOPの話をしている - Aspect Oriented Programming

は、ここで私はラムダとして "仕事" を渡すことによってそれを行う方法は次のとおりです。

public partial static class Aspect 
{ 
    public static T HandleFaultException<T>(Func<T> fn) 
    { 
    try 
    { 
     return fn(); 
    } 
    catch(FaultException ex) 
    { 
     Logger.log(ex); 
     throw; 
    } 
    } 
} 

そして、それを使用する:

return Aspect.HandleFaultException(() => 
    { 
    // call WCF 
    } 
); 

同じ目標を達成するための他の方法、さらには市販の製品もありますが、私はこの方法が最も明白で柔軟な方法であると考えています。

たとえば、あなたはあなたのためのクライアントを作成し、配置面書き込むことができます。

public partial static class Aspect 
{ 
    public static T CallClient<T>(Func<Client, T> fn) 
    { 
    using (var client = ... create client ...) 
    { 
     return fn(client); 
    } 
    } 
} 

とそうは:

return Aspect.CallClient(client => 
    { 
    return client.Method(...); 
    } 
); 

そして、あなたは通常、必要なすべての側面をラップすることができます1つのマスターアスペクトを適用して作成します。

0

は、一般的に言えば、あなたはあなたのための冗長な仕事をして、いくつかの例外ハンドラを書くことができます:

public abstract class ExceptionHandler 
{ 
    /// Returns true if the exception is handled; otherwise returns false. 
    public abstract bool Handle(Exception ex); 

    protected void Log(Exception ex) 
    { 
     // Log exception here 
    } 
} 

public class FileExceptionHandler : ExceptionHandler 
{ 
    public override bool Handle(Exception ex) 
    { 
     this.Log(ex); 

     // Tries to handle exceptions gracefully 
     if (ex is UnauthorizedAccessException) 
     { 
      // Add some logic here (for example encapsulate the exception) 
      // ... 
      return true; 
     } 
     else if (ex is IOException) 
     { 
      // Another logic here 
      // ... 
      return true; 
     } 

     // Did not handled the exception... 
     return false; 
    } 
} 

public class Program 
{ 
    private static void Main(string[] args) 
    { 
     try 
     { 
      // File manipulation 
      throw new IOException(); 
     } 
     catch (Exception ex) 
     { 
      if (!new FileExceptionHandler().Handle(ex)) 
      { 
       // Exception not handled, so throw exception 
       throw; 
      } 
     } 

     Console.WriteLine("end"); 
    } 
} 
0

あなたの質問は、あなたが動作するためにあなたがそのボイラーを繰り返すことができてより速くあなたの現在のパターンを作成する方法についてです場合プレートコードを作成することにより、Snippet

<CodeSnippets 
    xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"> 
    <CodeSnippet Format="1.0.0"> 
     <Header> 
      <Title> 
       trylog 
      </Title> 
      <Shortcut> 
       trylog 
      </Shortcut> 
     </Header> 
     <Snippet> 
      <Code Language="CSharp"> 
       <![CDATA[try { 
    // do some work 

} 
catch(Exception ex) 
{ 
    Logger.log(ex); 

    // actually will be Fault Exception but you get the idea. 
    throw ex; 
}]]> 
      </Code> 
     </Snippet> 
    </CodeSnippet> 
</CodeSnippets> 
関連する問題