2013-03-04 30 views
10

Tôi có dịch vụ WCF ghi nhật ký bất kỳ ngoại lệ nào và sau đó ném chúng dưới dạng FaultExceptions.Thiết kế mẫu/C# lừa cho bit lặp lại mã

Tôi đang thực hiện rất nhiều sự lặp lại, ví dụ: trong mỗi phương thức dịch vụ.

try { 
    // do some work 

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

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

Tôi đang tìm cách thanh lịch hơn để thực hiện việc này khi tôi cắt và dán thử/nắm bắt trong mỗi dịch vụ.

Có mẫu thiết kế/thủ thuật C# nào có thể được sử dụng để làm cho điều này thanh lịch hơn không?

+16

Lưu ý rằng "ném ex;" mất ngăn xếp cuộc gọi ban đầu, trong khi "ném"; không làm. – Polyfun

+1

Cơ thể của thử cũng có bắt được không? – christopher

+1

Bạn đang xem xét Aspect định hướng lập trình ở đây - http://msdn.microsoft.com/en-us/library/aa288717%28v=vs.71%29.aspx. Nhiều giải pháp của bên thứ ba như PostSharp có các khía cạnh Xử lý ngoại lệ thực hiện chính xác điều này. Một giải pháp khác (tồi tệ hơn) là bắt tất cả các ngoại lệ ở cấp ứng dụng (ví dụ như AppDomain_UnhandledException) thay vì có các khối catch thử cục bộ. Tôi nói tồi tệ hơn vì nó có hiệu quả trong việc xử lý ngoại lệ, hoặc vứt bỏ mã của bạn bằng try/catch (throw) – dash

Trả lời

1

Template method pattern chỉ thực hiện việc này và bạn có thể dễ dàng triển khai nó mà không cần kế thừa bằng cách sử dụng các đại biểu của C# (hoặc lambdas).

0

Nếu bạn chỉ đơn giản là ném, vì vậy tuyên truyền ngoại lệ trên đỉnh của ngăn xếp gọi điện thoại, bạn có thể tránh xử lý nó trên mọi cấp độ sâu, chỉ cần bắt nó trên hầu hết các cấp cao nhất (có thể) và đăng nhập. Hãy nhớ rằng đối tượng Exception cũng chứa stack-trace.

Nếu bạn, bằng cách này, cần bắt, ở mọi cấp độ, hãy nhớ sử dụng throw, vì vậy ngăn xếp cuộc gọi sẽ không bị ảnh hưởng, thay vào đó theo cách bạn sử dụng, nó sẽ.

0

Bạn cũng có thể thử đăng ký sự kiện Application_Error trong tệp global.asax của mình.

Đối với các ứng dụng dành cho máy tính để bàn, có sự kiện UnhandledException trong AppDomain.

+0

@Downvoters: Xin vui lòng nhận xét những gì sai với giải pháp này! – Carsten

2

Đối với WCF cụ thể, bạn có thể xem xét thêm ErrorHandler riêng. Điều này cho phép bạn "tiêm" mã của riêng bạn để được thực hiện mỗi lần bất kỳ phương thức nào ném một ngoại lệ.

Bạn có thể thiết lập nó như thế này:

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) 
    { 
    } 
} 

này cũng cho phép bạn ném tất cả các loại ngoại lệ và chuyển đổi chúng sang Fault Exceptions, được xử lý đúng cách bởi WCF sau này, mà không sửa đổi lớp doanh nghiệp của bạn hoặc áp dụng mã try/catch và chuyển đổi chúng ở đó.

5

Chúng tôi có một vấn đề tương tự trong một trong các dịch vụ WCF của chúng tôi, mà tôi đã giải quyết bằng cách sử dụng một đại biểu helper:

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

Cách sử dụng:

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

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

Bạn vẫn phải lặp lại các wrapper , nhưng đó là mã ít hơn nhiều và bạn có thể sửa đổi logic trong try..catch ở một nơi.

9

Bạn đang nói về AOP - Aspect Oriented Programming

Dưới đây là cách tôi làm điều đó bằng cách thông qua các "tác phẩm" như một lambda:

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

Sau đó, để sử dụng nó:

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

Có nhiều cách khác để đạt được cùng một mục tiêu, và thậm chí một số sản phẩm thương mại, nhưng tôi thấy cách này là rõ ràng và linh hoạt nhất.

Ví dụ, bạn có thể viết một khía cạnh mà tạo ra và disposes client dành cho bạn:

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

và như vậy:

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

Và sau đó, bạn có thể bọc tất cả các khía cạnh bạn thường muốn để áp dụng và tạo một khía cạnh chính.

0

Nói chung, bạn có thể viết một số bộ xử lý ngoại lệ mà không được công việc không cần thiết cho bạn:

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

Nếu câu hỏi của bạn là về làm thế nào để thực hiện mô hình hiện tại của bạn nhanh hơn để bạn có thể làm việc với bạn có thể lặp lại nồi hơi mà mã tấm bằng cách tạo một mã số 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> 
Các vấn đề liên quan