2011-12-16 47 views
5

Tôi đang làm việc trên một ứng dụng winform sẽ truy cập dịch vụ WCF tự lưu trữ dưới dạng dịch vụ cửa sổ. Tôi đang sử dụng ChannelFactory thay vì tham chiếu dịch vụ. Tôi đã thành công trong việc kết nối và gọi dịch vụ WCF. Vấn đề là khi tôi để ứng dụng ở chế độ không hoạt động trong 20 phút và sau đó thử thực hiện một cuộc gọi khác. Tôi nhận được lỗi sau:Thực hành tốt nhất với WCF ChannelFactory và thời gian chờ kết nối

"Kết nối ổ cắm bị hủy. Điều này có thể do lỗi xử lý tin nhắn của bạn hoặc thời gian chờ bị vượt quá bởi máy chủ từ xa hoặc sự cố tài nguyên mạng cơ bản. 00: 00: 59.9489970 '. "

Tôi đang tìm cách thực hành tốt nhất về quản lý kết nối. Tôi hiện đã tạo một hàm gọi là PrepareWCFConnection (xem bên dưới) để kiểm tra trạng thái của kênh và ChannelFactory. Tôi gọi phương thức này trước khi tôi thực hiện bất kỳ cuộc gọi nào đến các dịch vụ WCF. Có cách nào tốt hơn để xử lý việc này không?

 public bool PrepareWCFConnection() 
    { 
     if ((channelFactory == null) || 
      (channelFactory.State == CommunicationState.Faulted) || 
      (channelFactory.State != CommunicationState.Opened)) 
     { 
      channelFactory = new ChannelFactory<IService1>(new NetTcpBinding(), endpointAddress); 
     } 


     if ((proxy == null) || 
      (((IClientChannel)proxy).State == CommunicationState.Faulted) || 
      (((IClientChannel)proxy).State != CommunicationState.Opened)) 
     { 
      proxy = channelFactory.CreateChannel(endpointAddress); 
      ((IClientChannel)proxy).Open(); 
     } 

     return true; 
    } 
+0

Thử nghiệm khác của mã trên đã chứng tỏ nó không hoạt động. Cả ChannelFactory và kênh đều mở nhưng tôi vẫn nhận được lỗi này sau khi cho phép hệ thống không hoạt động: Kết nối socket đã bị hủy bỏ. Điều này có thể do lỗi xử lý tin nhắn của bạn hoặc thời gian chờ nhận được vượt quá bởi máy chủ từ xa hoặc sự cố tài nguyên mạng cơ bản. Thời gian chờ của ổ cắm cục bộ là '00: 00: 59.9479970 '. – econner

+1

Đây là một liên kết từ MSDN cho thấy việc tạo kênh và kênh riêng, thực hiện cuộc gọi và đóng kênh rồi đóng nhà máy kênh. Tuy nhiên, nếu bạn sử dụng khoản tín dụng để xác thực, sẽ không đóng kênh sau mỗi cuộc gọi phương thức và tạo lại kênh trước khi mỗi phương thức tốn kém về tài nguyên và thời gian? http://msdn.microsoft.com/en-us/library/ms734681.aspx – econner

+0

Sau khi thử nghiệm thêm, trước tiên tôi bắt đầu cuộc gọi đến dịch vụ WCF bằng PrepareWCFConnection() ... sau đó gọi phương thức dịch vụ của tôi và sau đó gọi ((IClientChannel) proxy) .Đóng(); Điều này sẽ đóng kết nối kênh và sau đó tạo kênh mới cho mỗi cuộc gọi phương thức. Đây có phải là phương pháp hay nhất không? – econner

Trả lời

4

Nếu bạn muốn sử dụng một kênh hiện tại bạn cần để Giữ kênh sống bằng cách ping dịch vụ mỗi 9 minutes.I nghĩ mặc định nhận được thời gian chờ là 10 phút, do đó kênh này sẽ bị ngắt kết nối nếu nó được giữ nhàn rỗi vượt quá điều này. Hoặc bạn có thể sử dụng các phiên đáng tin cậy để giữ cho các kênh còn sống.

Nếu bạn không cần gọi lại trên cùng một kênh, tốt nhất là bạn đóng kênh khi bạn đã hoàn tất và tạo lại kênh mới cho mọi thao tác dịch vụ.Không tốn kém để tạo kênh.Bạn có thể lưu vào bộ nhớ cache nhà máy kênh, nhưng tạo kênh cho mọi cuộc gọi.

+1

điểm tốt: _Bạn có thể lưu vào bộ nhớ cache kênh nhà máy, nhưng tạo kênh cho mọi cuộc gọi_. – baraban

1

Tôi biết câu hỏi này khá cũ nhưng tôi thấy nó không thực sự được trả lời. Có hai timeouts (cũng chỉ 1 nếu bạn không sử dụng tin nhắn đáng tin cậy), bạn nên quan tâm đến khi nói đến kênh thời gian ra ngoài. Về phía dịch vụ, bạn có "ReceiveTimeout" được kích hoạt nếu không nhận được tin nhắn ứng dụng nào trong khoảng thời gian chờ. Mặc định cho thời gian chờ này là 10 phút.

Ngoài ra còn có "InactivityTimeout" chỉ được sử dụng nếu "TrustedSession" được bật. Thời gian chờ này là thời lượng tối đa mà kênh cho phép bên giao tiếp khác không gửi bất kỳ tin nhắn nào trước khi gây lỗi cho kênh.

Để tăng tuổi thọ của kênh, tôi khuyên bạn nên bật "TrustedSession" và sau đó đặt cả "ReceiveTimeout" & "InactivityTimeout" thành giá trị cao hơn. ReliableSession giữ cho kênh sống bằng cách gửi các thông điệp cấp cơ sở của ILM (như thông điệp về mức cơ sở hạ tầng) giống như của những người sống sót (cũng được gửi đi). Nếu không nhận được thông báo tiếp tục hoặc ALM (thông báo mức ứng dụng) trước khi "InactivityTimeout" hết hạn thì kênh sẽ bị lỗi.

Ngoài ra nếu không nhận được ALM (thông báo mức ứng dụng) trước khi "ReceiveTimeout" hết hạn, kênh sẽ bị lỗi.

Vì vậy, bạn nên tăng cả hai thời gian chờ lên cùng một giá trị HOẶC đặt "ReceiveTimeout" thành giá trị cao hơn "InactivityTimeout".

Lưu ý phụ, đặt "ReceiveTimeout" sẽ không có hiệu lực khi được đặt ở phía máy khách, nó chỉ là thời gian chờ của dịch vụ. Nhưng khi sử dụng TrustedSession ở phía dịch vụ, khách hàng cũng phải triển khai nó như vậy:

NetTcpBinding binding = new NetTcpBinding 
     { 
      ReliableSession = { Enabled = true },    
      SendTimeout = TimeSpan.FromMinutes(1) 
     }; 

     binding.ReliableSession.InactivityTimeout = TimeSpan.Parse("24.20:31:23.6470000"); 

Và ứng dụng.cấu hình ở phía bên dịch vụ sẽ giống như thế này:

<bindings> 
    <netTcpBinding> 
     <binding name="netTestTcpBinding" 
       receiveTimeout="24.20:31:23.6470000"> 
     <reliableSession inactivityTimeout="24.20:31:23.6470000" 
         enabled="true" /> 
     </binding> 
    </netTcpBinding> 
    </bindings> 
<services> 
    <service> 
    <endpoint address="IServiceContract" 
       binding="netTcpBinding" 
       bindingConfiguration="netTestTcpBinding" 
       name="serviceContractTcpBinding"/> 
    <host> 
     <baseAddresses> 
      <add baseAddress="net.tcp://localhost:12001/" /> 
     </baseAddresses> 
    </host> 
    </service>     
</services> 
0

Một giải pháp khá thẳng về phía trước để tái sử dụng kênh của bạn, mà không cần bỏ phiếu hoặc làm công cụ ưa thích nó chỉ chăm sóc của cuộc gọi cuối cùng để kênh của bạn và kiểm tra wcfC. Binding.ReceiveTimeout để tạo lại nó nếu cần thiết, một cái gì đó như:

TimeSpan timeSpan = DateTime.Now - LastCallTime; 
    if (timeSpan.TotalSeconds > wcfC.Binding.ReceiveTimeout.TotalSeconds || wcfC.State != CommunicationState.Opened) 
    { 
     wcfC.Abort(); 
     wcfC = new WCFChannel(); 

    }  
    LastCallTime = DateTime.Now; 
Các vấn đề liên quan