2009-09-15 28 views
28

Tôi đang cố gắng xây dựng một SOA nơi khách hàng có thể thực hiện các truy vấn chạy dài trên máy chủ và máy chủ trả lời bằng cách sử dụng gọi lại.Phát hiện thân chủ chết trong Hợp đồng Duplex WCF

Tôi muốn có thể phát hiện xem máy khách có ngắt kết nối (thông qua tắt máy do người dùng khởi tạo, ngoại lệ không được giải quyết hoặc mất kết nối mạng) để máy chủ có thể chọn hủy yêu cầu đắt tiền.

Tôi đang thử nghiệm nhiều trường hợp lỗi khác nhau nhưng tôi dường như không thể xử lý sự kiện nhất định để kích hoạt.

Trường hợp lỗi được kiểm tra: Giết quá trình khách hàng Sau khi yêu cầu. Sử dụng chương trình như CurrPorts để đóng Kết nối TCP.

Mã kiểm tra:

using System; 
using System.ServiceModel; 
using System.Threading; 

namespace WCFICommunicationObjectExperiments 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var binding = new NetTcpBinding(SecurityMode.None); 

      var serviceHost = new ServiceHost(typeof (Server)); 
      serviceHost.AddServiceEndpoint(typeof (IServer), binding, "net.tcp://localhost:5000/Server"); 
      serviceHost.Open(); 
      Console.WriteLine("Host is running, press <ENTER> to exit."); 
      Console.ReadLine(); 
     } 

    } 

    [ServiceContract(CallbackContract = typeof(IClient))] 
    public interface IServer 
    { 
     [OperationContract] 
     void StartProcessing(string Query); 
    } 

    public interface IClient 
    { 
     [OperationContract] 
     void RecieveResults(string Results); 
    } 

    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)] 
    public class Server : IServer 
    { 

     public void StartProcessing(string Query) 
     { 
      Thread.Sleep(5000); 

      //Callback Channel 
      var clientCallback = OperationContext.Current.GetCallbackChannel<IClient>(); 
      var clientCallbackCommunicationObject = ((ICommunicationObject) clientCallback); 
      EventHandler faultedHandlerCallback = (o, s) => Console.WriteLine("Client Channel Faulted."); 
      EventHandler closedHandlerCallback = (o, s) => Console.WriteLine("Client Channel Closed."); 
      clientCallbackCommunicationObject.Faulted += faultedHandlerCallback; 
      clientCallbackCommunicationObject.Closed += closedHandlerCallback; 

      //Request Channel 
      var requestChannel = OperationContext.Current.Channel; 
      EventHandler faultedHandlerRequest = (o, s) => Console.WriteLine("Request Channel Faulted."); 
      EventHandler closedHandlerRequest = (o, s) => Console.WriteLine("Request Channel Closed."); 
      requestChannel.Faulted += faultedHandlerRequest; 
      requestChannel.Closed += closedHandlerRequest; 

      try 
      { 
       clientCallback.RecieveResults("42."); 
      } 
      catch (CommunicationObjectAbortedException ex) 
      { 
       Console.WriteLine("Client Aborted the connection"); 
      } 
      catch (CommunicationObjectFaultedException ex) 
      { 
       Console.WriteLine("Client Died."); 
      } 
      clientCallbackCommunicationObject.Faulted -= faultedHandlerCallback; 
      clientCallbackCommunicationObject.Faulted -= closedHandlerCallback; 
      requestChannel.Faulted -= faultedHandlerRequest; 
      requestChannel.Closed -= closedHandlerRequest; 
     } 
    } 

    public class ClientToTestStates : IClient 
    { 
     private IServer m_Server; 

     private readonly ManualResetEvent m_ReceivedEvent = new ManualResetEvent(false); 
     private readonly ManualResetEvent m_ChannelFaulted = new ManualResetEvent(false); 
     private readonly ManualResetEvent m_ChannelClosed = new ManualResetEvent(false); 

     public ClientToTestStates() 
     { 
      var binding = new NetTcpBinding(SecurityMode.None); 
      var channelFactory = new DuplexChannelFactory<IServer>(this, binding, new EndpointAddress("net.tcp://localhost:5000/Server")); 
      m_Server = channelFactory.CreateChannel(); 
      ((ICommunicationObject)m_Server).Open(); 
      ((ICommunicationObject)m_Server).Faulted += ChannelFaulted; 
      ((ICommunicationObject)m_Server).Closed += ChannelClosed; 

      m_Server.StartProcessing("What is the answer?"); 

      WaitHandle.WaitAny(new WaitHandle[] {m_ReceivedEvent, m_ChannelFaulted, m_ChannelClosed}); 
     } 

     void ChannelFaulted(object sender, EventArgs e) 
     { 
      m_ChannelFaulted.Set(); 
      Console.WriteLine("Channel Faulted."); 
     } 

     void ChannelClosed(object sender, EventArgs e) 
     { 
      m_ChannelClosed.Set(); 
      Console.WriteLine("Channel Closed."); 
     } 


     public void RecieveResults(string results) 
     { 
      m_ReceivedEvent.Set(); 
      Console.WriteLine("Recieved Results {0}", results); 
     } 
    } 
} 

các thực hành tốt nhất để xử lý các loại trường hợp thất bại là gì? Tôi muốn có thể sử dụng kết nối tcp cơ bản để phát hiện một số trong những điều này.

+0

Có bạn đã thử bật Độ tin cậy? TCP cung cấp độ tin cậy điểm-điểm.
Độ tin cậy của tin nhắn (qua Độ tin cậy của WS) cung cấp độ tin cậy từ đầu đến cuối.
Và lần lượt tôi tin rằng sẽ thông báo cho bạn khi một trong hai bên "biến mất" một cách vô thức. Đối với các phương tiện vận chuyển hỗ trợ nó, cách tốt nhất là luôn bật độ tin cậy, mặc dù một số mạng 'goo' có thể không hỗ trợ nó –

Trả lời

14

Trong cuốn sách 'Lập trình WCF', Juval Lowy giải thích rằng WCF không cung cấp mechansim để quản lý cuộc gọi dịch vụ và điều này phải được quản lý bởi dịch vụ và khách hàng một cách rõ ràng. Nếu dịch vụ cố gắng gọi một cuộc gọi lại đã được đóng trên máy khách, một ObjectDisposedException sẽ được ném vào kênh dịch vụ.

Anh khuyên bạn nên thêm phương thức Kết nối và Ngắt kết nối vào hợp đồng dịch vụ - vì cuộc gọi lại phải được cung cấp cho dịch vụ khi chúng được gọi, dịch vụ có thể quản lý cuộc gọi lại của khách hàng. Sau đó nó được gửi tới máy khách để đảm bảo rằng nó gọi Ngắt kết nối khi nó không còn muốn nhận các cuộc gọi lại từ dịch vụ và dịch vụ phải xử lý bất kỳ ngoại lệ nào khi gọi các cuộc gọi lại đến máy khách.

+1

Cảm ơn thông tin. Trong trường hợp thất bại của khách hàng không mong muốn, nơi người ta không thể mong đợi Disconnect() để được gọi là những gì có thể được thực hiện để phát hiện lỗi đó sớm ở phía máy chủ để giải phóng tài nguyên quý giá? – Sindhudweep

+1

cho rằng hệ điều hành biết rằng các kết nối TCP đã không có các gói tin còn sống. Nó sẽ có thể cho một máy chủ WCF để biết khách hàng đã biến mất. Vì vậy, nên có một câu trả lời tốt hơn sau đó điều này. Tôi chỉ không biết nó là gì! –

+0

Hệ điều hành có thể sử dụng kết nối TCP. Trong các thử nghiệm của tôi, tôi đã sử dụng ràng buộc Net.tcp và tôi đã nhận được các sự kiện bị lỗi do kênh. Thật không may nếu kết nối tcp là một máy đang phục vụ như một relay (sử dụng chuyển tiếp từ xa của SSH với ràng buộc toàn cục), hệ điều hành không nhìn thấy kết nối TCP đóng (vì kết nối tới máy tiếp sức không thực sự đóng). Điều này đã gây ra hành vi kỳ lạ mà tôi quan sát được trong bài kiểm tra của tôi. – Sindhudweep

12

thử này để kiểm tra nếu đối tượng gọi lại vẫn còn hợp lệ:

(((ICommunicationObject)myCallbackObject).State == CommunicationState.Opened) 

myCallbackObject trong trường hợp này là các đối tượng thông qua đó bạn có thể thực hiện gọi lại, tức là thực hiện hợp đồng callback

+5

giải pháp này không được khuyến nghị vì kênh gọi lại có thể bị lỗi ở giữa thời gian bạn kiểm tra trạng thái và thời gian bạn làm bất kỳ điều gì với kênh. – LxL

+2

Vâng, bạn vẫn nên xử lý bất kỳ ngoại lệ nào vì không thực sự là một cách để kiểm tra chắc chắn. –

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