2010-09-18 43 views
6

Tôi đang sử dụng netNamedPipeBinding để thực hiện liên lạc WCF liên thông từ một ứng dụng cửa sổ đến dịch vụ cửa sổ.Ngoại lệ WCF nhận được khi đóng kết nối với các cuộc gọi lại đang sử dụng

Bây giờ ứng dụng của tôi đang chạy tốt trong tất cả các tài khoản khác (sau khi đấu với phần ngoại lệ WCF của tôi vì bất kỳ ai đã làm việc với WCF đều biết ..) nhưng lỗi này là một trong số đó tỏ ra khá kiên cường.

Để vẽ hình ảnh về kịch bản của tôi: dịch vụ cửa sổ của tôi có thể được xếp hàng để thực hiện một số công việc tại bất kỳ thời điểm nào thông qua một nút được nhấn trong ứng dụng cửa sổ và sau đó nói qua số netNamedPipeBinding. -truyền thông) nếu bạn không quen thuộc và bắt đầu một yêu cầu để thực hiện công việc này, (trong trường hợp này là một thủ tục tải lên tập tin) nó cũng ném callbacks (sự kiện) mỗi vài giây khác nhau, từ tiến trình tập tin đến tốc độ chuyển vv. ứng dụng cửa sổ, vì vậy có một số tích hợp máy chủ-máy chủ khá chặt chẽ; đây là cách tôi nhận được sự tiến bộ của tôi về những gì đang chạy trong cửa sổ dịch vụ của tôi trở lại ứng dụng cửa sổ của tôi.

Bây giờ, tất cả là tuyệt vời, các vị thần WCF tương đối hài lòng với tôi ngay bây giờ ngoài một ngoại lệ khó chịu mà tôi nhận được mỗi khi tôi tắt ứng dụng sớm (đó là một kịch bản hoàn toàn hợp lệ). Trong khi chuyển đang diễn ra, và callbacks được bắn khá nặng nề, tôi nhận được lỗi này:

System.ServiceModel.ProtocolException: 
    The channel received an unexpected input message with Action 
    'http://tempuri.org/ITransferServiceContract/TransferSpeedChangedCallback' 
    while closing. You should only close your channel when you are not expecting 
    any more input messages. 

Bây giờ tôi hiểu lỗi đó, nhưng tiếc là tôi không thể đảm bảo để đóng kênh của tôi sau không bao giờ nhận được bất kỳ messsages đầu vào hơn, như người dùng có thể tắt ứng dụng bất cứ lúc nào do đó công việc sẽ vẫn tiếp tục trong nền của dịch vụ windows (giống như cách hoạt động của trình quét vi-rút). Người dùng có thể bắt đầu và đóng ứng dụng công cụ quản lý chiến thắng nhiều như họ muốn mà không bị nhiễu.

Bây giờ lỗi, tôi nhận ngay sau khi thực hiện cuộc gọi Unsubscribe() là cuộc gọi cuối cùng thứ hai trước khi chấm dứt ứng dụng và những gì tôi tin là cách ưu tiên để ngắt kết nối ứng dụng khách WCF. Tất cả việc hủy đăng ký trước khi đóng kết nối chỉ đơn giản là xóa id ứng dụng khỏi một mảng được lưu trữ cục bộ trên dịch vụ wcf dịch vụ giành chiến thắng (vì đây là một cá thể ĐƯỢC CHIA SẺ bởi cả dịch vụ giành chiến thắng và ứng dụng windows làm dịch vụ giành chiến thắng có thể thực hiện công việc tại các sự kiện theo lịch trình của chính nó) và sau khi loại bỏ mảng id khách hàng tôi thực hiện, những gì tôi hy vọng (cảm thấy) nên là một ngắt kết nối sạch sẽ. Kết quả của việc này, ngoài việc nhận được ngoại lệ, ứng dụng của tôi bị treo, giao diện người dùng trong tổng số khóa, thanh tiến trình và mọi thứ ở giữa, với tất cả các dấu hiệu chỉ đến tình trạng đua hoặc bế tắc WCF [tiếng thở dài], nhưng bây giờ tôi khá hiểu biết và tôi nghĩ đây là một tình huống tương đối biệt lập và đọc ngoại lệ như-là, tôi không nghĩ rằng đó là vấn đề 'chủ đề', vì nó nói thêm một vấn đề ngắt kết nối sớm sau đó xoắn tất cả các chủ đề của tôi vào tình trạng lộn xộn, có lẽ gây ra khóa.

Tiếp cận của tôi Unsubscribe() trên client trông như thế này:

public void Unsubscribe() 
    { 
     try 
     { 
      // Close existing connections 
      if (channel != null && 
       channel.State == CommunicationState.Opened) 
      { 
       proxy.Unsubscribe(); 
      } 
     } 
     catch (Exception) 
     { 
      // This is where we receive the 'System.ServiceModel.ProtocolException'. 
     } 
     finally 
     { 
      Dispose(); 
     } 
    } 

Dispose() phương pháp của tôi, mà nên thực hiện ngắt kết nối sạch:

public void Dispose() 
    { 
     // Dispose object 
     if (channel != null) 
     { 
      try 
      { 
       // Close existing connections 
       Close(); 
       // Attempt dispose object 
       ((IDisposable)channel).Dispose(); 
      } 
      catch (CommunicationException) 
      { 
       channel.Abort(); 
      } 
      catch (TimeoutException) 
      { 
       channel.Abort(); 
      } 
      catch (Exception) 
      { 
       channel.Abort(); 
       throw; 
      } 
     } 
    } 

Và các dịch vụ WCF Subscription() đối tác và lớp thuộc tính (để tham khảo) trên dịch vụ windows máy chủ (không có gì phức tạp ở đây và ngoại lệ của tôi xảy ra phía khách hàng):

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, 
    ConcurrencyMode = ConcurrencyMode.Multiple)] 
    public class TransferService : LoggableBase, ITransferServiceContract 
    { 
     public void Unsubscribe() 
     { 
      if (clients.ContainsKey(clientName)) 
      { 
       lock (syncObj) 
       { 
        clients.Remove(clientName); 
       } 
      } 

#if DEBUG 
      Console.WriteLine(" + {0} disconnected.", clientName); 
#endif 
     } 
     ... 
    } 

Giao diện của:

[ServiceContract(
    CallbackContract = typeof(ITransferServiceCallbackContract), 
    SessionMode = SessionMode.Required)] 
public interface ITransferServiceContract 
{ 
    [OperationContract(IsInitiating = true)] 
    bool Subscribe(); 

    [OperationContract(IsOneWay = true)] 
    void Unsubscribe(); 
    ... 
} 

Interface hợp đồng gọi lại, nó không làm bất cứ điều gì rất thú vị, chỉ cần gọi sự kiện thông qua các đại biểu vv Lý do tôi bao gồm này là để hiển thị bạn thuộc tính của tôi. Tôi đã làm giảm bớt một bộ bế tắc đã được bao gồm UseSynchronizationContext = false:

[CallbackBehavior(UseSynchronizationContext = false, 
ConcurrencyMode = ConcurrencyMode.Multiple)] 
public class TransferServiceCallback : ITransferServiceCallbackContract 
{ ... } 

Thực sự hy vọng ai đó có thể giúp tôi! Cảm ơn rất nhiều = :)

+0

Tôi không biết về vấn đề cụ thể, nhưng để biết những lộn xộn luồng âm thanh * có thể * do cách WCF sử dụng đồng bộ ngữ cảnh (đó là thông qua hình thức trong winforms vv). –

+0

Cảm ơn Marc, yep đã bắt được tôi và tôi đã giảm bớt một tập hợp các deadlocks bằng cách đọc về vấn đề đó, mẹo để đặt 'UseSynchronizationContext = false' trên hợp đồng gọi lại;) Tôi sẽ thêm điều này vào ví dụ của mình. – GONeale

+0

ah, đúng; tốt để xem bạn đã có nó bảo hiểm, p –

Trả lời

11

OH trời ơi, tôi đã tìm thấy vấn đề.

Ngoại lệ đó không liên quan gì đến ứng dụng chưa hoàn tất, đó chỉ là một ngoại lệ đề phòng mà bạn có thể nắm bắt một cách an toàn.

Bạn sẽ không tin được, tôi đã dành khoảng 6 giờ bật và tắt trên lỗi này, hóa ra là channel.Close() khóa chờ các yêu cầu WCF đang chờ xử lý hoàn thành (không bao giờ hoàn thành cho đến khi quá trình chuyển hoàn tất! đánh bại mục đích!)

Tôi vừa mới đi đến vạch đứt gãy sau hàng, vấn đề của tôi là nếu tôi quá chậm ..... nó sẽ không bao giờ treo, bởi vì bằng cách nào đó kênh sẽ có sẵn để đóng (thậm chí trước đây việc chuyển giao đã hoàn thành) vì vậy tôi phải phá vỡ F5 và sau đó nhanh chóng bước để bắt hang, và đó là dòng nó kết thúc. Tôi bây giờ chỉ cần áp dụng một giá trị thời gian chờ cho hoạt động Close() và bắt nó với một TimeoutException và sau đó khó hủy bỏ kênh nếu nó không thể tắt một cách kịp thời!

Xem mã sửa chữa:

private void Close() 
{ 
    if (channel != null && 
     channel.State == CommunicationState.Opened) 
    { 
     // If cannot cleanly close down the app in 3 seconds, 
     // channel is locked due to channel heavily in use 
     // through callbacks or the like. 
     // Throw TimeoutException 
     channel.Close(new TimeSpan(0, 0, 0, 3)); 
    } 
} 

public void Dispose() 
{ 
    // Dispose object 
    if (channel != null) 
    { 
     try 
     { 
      // Close existing connections 
      // ***************************** 
      // This is the close operation where we perform 
      //the channel close and timeout check and catch the exception. 
      Close(); 

      // Attempt dispose object 
      ((IDisposable)channel).Dispose(); 
     } 
     catch (CommunicationException) 
     { 
      channel.Abort(); 
     } 
     catch (TimeoutException) 
     { 
      channel.Abort(); 
     } 
     catch (Exception) 
     { 
      channel.Abort(); 
      throw; 
     } 
    } 
} 

Tôi rất vui khi có lỗi này cuối cùng đã qua và thực hiện với! Ứng dụng của tôi hiện đang tắt sạch sau khoảng thời gian chờ 3 giây bất kể trạng thái dịch vụ WCF hiện tại, tôi hy vọng tôi có thể giúp một người nào đó khác nhận thấy mình đang gặp phải vấn đề tương tự.

Graham

+0

_Đó là ngoại lệ không liên quan gì đến ứng dụng chưa xử lý, đó chỉ là một ngoại lệ phòng ngừa mà bạn có thể nắm bắt một cách an toàn._ Bạn có liên kết tham chiếu nói đến sự an toàn của việc nuốt phải ProtocolExceptions như thế này không? Tôi có chính xác cùng một vấn đề. – lesscode

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