2010-01-05 21 views
11

Khi một cá thể ClientBase<T> được sử dụng cho nhiều cuộc gọi dịch vụ WCF, nó có thể đưa kênh vào trạng thái bị lỗi (ví dụ: khi dịch vụ ngừng hoạt động).Làm thế nào để chữa lành các kênh WCF bị lỗi?

Tôi muốn tự động hàn kênh khi dịch vụ xuất hiện trở lại. Cách duy nhất tôi tìm thấy là gọi mã sau đây trước mỗi phương thức gọi:

if (clientBase.InnerChannel.State == CommunicationState.Faulted) 
{ 
     clientBase.Abort(); 
     ((IDisposable)clientBase).Dispose(); 
     clientBase = new SampleServiceClientBase(); 
} 

Tôi có cảm giác rằng đây không phải là cách phù hợp để thực hiện. Bất cứ ai có một ý tưởng tốt hơn?

Trả lời

18

Bạn không thể. Khi kênh bị lỗi, nó bị lỗi vì tốt. Bạn phải tạo một kênh mới. Các kênh WCF là trạng thái (theo cách nói), do đó kênh bị lỗi có nghĩa là trạng thái có thể bị hỏng.

Những gì bạn có thể làm là đặt logic bạn đang sử dụng thành một phương pháp hữu ích:

public static class Service<T> where T : class, ICommunicationObject, new() 
{ 
    public static void AutoRepair(ref T co) 
    { 
     AutoRepair(ref co,() => new T()); 
    } 

    public static void AutoRepair(ref T co, Func<T> createMethod) 
    { 
     if ((co != null) && (co.State == CommunicationState.Faulted)) 
     { 
      co.Abort(); 
      co = null; 
     } 
     if (co == null) 
     { 
      co = createMethod(); 
     } 
    } 
} 

Sau đó, bạn có thể gọi dịch vụ của bạn như sau:

Service<SampleServiceClient>.AutoRepair(ref service, 
    () => new SampleServiceClient(someParameter)); 
service.SomeMethod(); 

Hoặc nếu bạn muốn sử dụng hàm tạo parameterless mặc định, chỉ:

Service<SampleServiceClient>.AutoRepair(ref service); 
service.SomeMethod(); 

Vì nó cũng xử lý trường hợp t dịch vụ của anh ta là null, bạn không cần phải khởi tạo dịch vụ trước khi gọi.

Khá nhiều điều tốt nhất tôi có thể cung cấp. Có thể ai đó khác có cách tốt hơn.

+1

Bạn cũng cần T để triển khai IDisposable? –

+0

@DavidGardiner: Không nếu nó triển khai 'ICommunicationObject'. Việc thực hiện 'Dispose' trên các kênh WCF thực sự là một phần của vấn đề. – Aaronaught

+0

Nhưng giao diện ICommunicationObject (http://msdn.microsoft.com/en-us/library/system.servicemodel.icommunicationobject.aspx) không thực hiện IDisposable - vì vậy ví dụ trên sẽ không hoạt động nếu không đưa đồng vào IDisposable. –

0

Đây là những gì tôi hiện đang làm, nhưng tôi không thể nói đây là tùy chọn tốt nhất.

Tôi tạo lại proxy khi ngoại lệ bị phát hiện trong cuộc gọi.

try 
{ 
    ListCurrentProcesses(); 
} 
catch (TypeLoadException ex) 
{ 
    Debug.Print("Oops: " + ex.Message); 
    m_Proxy = new ProcessManagerProxy(); 
} 
catch (EndpointNotFoundException endpointEX) 
{ 
    Debug.Print("Oops: " + endpointEX.Message); 
    m_Proxy = new ProcessManagerProxy(); 
} 
catch (CommunicationException communicationEx) 
{ 
    Debug.Print("Oops: " + communicationEx.Message); 
    m_Proxy = new ProcessManagerProxy(); 
} 
+0

Không bao giờ bắt 'SystemException', ** đặc biệt ** nếu bạn không tái ném. Cây đó bao gồm các trường hợp như 'OutOfMemoryException' và' StackOverflowException'. Ngoài ra, bạn không xử lý đúng kênh cũ ở đây. – Aaronaught

+0

Đã hiểu. Đó chỉ là một ví dụ nhanh. Bạn có thấy một vấn đề lớn cho phép kênh thu thập thay vì xử lý rõ ràng kênh đó không? Tôi giả sử chúng tôi sẽ không thử lại hoạt động này 1000 lần trước khi chúng tôi từ bỏ. –

+0

Tôi đã thử nó và nó gây ra nhiều vấn đề hơn –

Các vấn đề liên quan