2009-11-04 37 views
5

Chúng tôi đang sử dụng WCF để xây dựng một dịch vụ web đơn giản mà sản phẩm của chúng tôi sử dụng để tải lên các tệp lớn qua liên kết WAN. Nó được coi là một HTTP PUT đơn giản, và nó hoạt động tốt cho hầu hết các phần.Tại sao WCF đọc luồng đầu vào EOF trên Close()?

Dưới đây là một phiên bản đơn giản của hợp đồng dịch vụ:

[ServiceContract, XmlSerializerFormat] 
public interface IReplicationWebService 
{ 
    [OperationContract] 
    [WebInvoke(Method = "PUT", UriTemplate = "agents/{sourceName}/epoch/{guid}/{number}/{type}")] 
    ReplayResult PutEpochFile(string sourceName, string guid, string number, string type, Stream stream); 
} 

Trong việc thực hiện hợp đồng này, chúng ta đọc dữ liệu từ stream và viết nó ra vào một tập tin. Điều này làm việc tuyệt vời, vì vậy chúng tôi đã thêm một số xử lý lỗi cho các trường hợp khi không có đủ dung lượng ổ đĩa để lưu trữ tệp. Đây là số tiền tương tự:

public ReplayResult PutEpochFile(string sourceName, string guid, string number, string type, Stream inStream) 
    { 
     //Stuff snipped 
     try 
     { 
      //Read from the stream and write to the file 
     } 
     catch (IOException ioe) 
     { 
      //IOException may mean no disk space 
      try 
      { 
       inStream.Close(); 
      } 
      // if instream caused the IOException, close may throw 
      catch 
      { 
      } 
      _logger.Debug(ioe.ToString()); 
      throw new FaultException<IOException>(ioe, new FaultReason(ioe.Message), new FaultCode("IO")); 
     } 
    } 

Để kiểm tra điều này, tôi đang gửi tệp 100 GB đến máy chủ không có đủ dung lượng cho tệp. Theo dự kiến, điều này sẽ ném một ngoại lệ, nhưng cuộc gọi đến inStream.Close() dường như bị treo. Tôi đã kiểm tra nó, và những gì thực sự xảy ra là cuộc gọi đến Close() thực hiện theo cách của mình thông qua hệ thống ống nước WCF cho đến khi nó đạt đến System.ServiceModel.Channels.DrainOnCloseStream.Close(), theo Reflector phân bổ bộ đệm Byte[] và tiếp tục đọc từ luồng cho đến khi nó ở EOF.

Nói cách khác, cuộc gọi Close đang đọc toàn bộ 100 GB dữ liệu thử nghiệm từ luồng trước khi quay trở lại!

Có thể tôi không cần gọi số Close() trên luồng này. Nếu đó là trường hợp tôi muốn có một lời giải thích là tại sao. Nhưng quan trọng hơn, tôi sẽ đánh giá cao nếu bất cứ ai có thể giải thích cho tôi lý do tại sao Close() hoạt động theo cách này, tại sao nó không được coi là lỗi và cách cấu hình lại WCF để không xảy ra.

Trả lời

4

.Close() được dự định là cách "an toàn" và "thân thiện" để ngừng hoạt động của bạn - và nó thực sự sẽ hoàn thành các yêu cầu hiện đang chạy trước khi tắt - theo thiết kế.

Nếu bạn muốn ném xuống búa tạ, hãy sử dụng .Abort() trên proxy máy khách của bạn (hoặc máy chủ dịch vụ) để thay thế. Điều đó chỉ tắt tất cả mọi thứ mà không kiểm tra và không được tốt đẹp về việc chờ đợi cho các hoạt động để hoàn thành.

+0

Cảm ơn bạn đã trả lời. Vấn đề với 'ServiceHost.Abort()' là nó hủy bỏ toàn bộ dịch vụ, không chỉ là cuộc gọi cụ thể đang được xử lý. Nếu có một số cách tôi có thể hướng dẫn WCF buộc phải đóng socket để đáp ứng với ngoại lệ ít nhất là theo cách đó tôi sẽ không phải chờ đợi cho việc chuyển giao để kết thúc trước khi khách hàng biết điều gì đó đã sai. – anelson

+0

Tôi không thể tìm ra bất kỳ cách nào để báo cáo lại một ngoại lệ cho máy khách HTTP mà không cần đợi máy khách hoàn thành việc gửi tệp, vì vậy tôi phải chấp nhận một giao diện PUT từng đoạn một. Tôi hy vọng sẽ tránh được điều đó nhưng tôi không nhìn thấy một cách xung quanh nó cho việc thực hiện HTTP tôi phải làm việc với – anelson

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