2010-12-16 34 views
8

Như đã đề cập trong một vài bài đăng khác (xem Tài liệu tham khảo bên dưới) Tôi đang cố tạo bộ lọc phản hồi để sửa đổi nội dung được tạo bởi một bộ lọc khác ứng dụng web.Làm cách nào để triển khai Bộ lọc Phản hồi HTTP để hoạt động trên toàn bộ nội dung cùng một lúc, không có chunking

Tôi có logic chuyển đổi chuỗi cơ bản hoạt động và được đóng gói thành các Bộ lọc lấy được từ một Bộ lọc chung. Tuy nhiên, logic phải hoạt động trên toàn bộ nội dung, không phải khối nội dung. Vì vậy, tôi cần phải cache các khối khi chúng được viết và thực hiện bộ lọc khi tất cả các ghi được hoàn thành.

Như hình dưới đây tôi đã tạo ra một ResponseFilter mới có nguồn gốc từ MemoryStream. On Write, nội dung được lưu vào MemoryStream khác. Trên Flush, toàn bộ nội dung, bây giờ trong MemoryStream được chuyển thành một chuỗi và logic Filter kick in. Nội dung sửa đổi sau đó được viết trở lại luồng gốc.

Tuy nhiên, theo mọi yêu cầu thứ hai (về cơ bản khi một Bộ lọc mới được khởi tạo qua bộ lọc trước đó), phương pháp Flush của bộ lọc trước đó đang được thực hiện. Tại thời điểm này, ứng dụng gặp sự cố trên phương thức _outputStream.Write() khi _cachedStream rỗng.

Trình tự của sự kiện như sau:

  1. Yêu cầu đầu tiên
  2. Viết phương pháp được gọi là
  3. phương pháp Flush được gọi
  4. phương thức Close được gọi
  5. phương thức Close được gọi là
  6. Tại thời điểm này, ứng dụng trả về và nội dung phù hợp được hiển thị.
  7. Yêu cầu thứ hai
  8. phương pháp được gọi là Flush
  9. ứng dụng bị treo trên _outputStream.Write. ArgumentOutOfRangeException (offset).
  10. Tiếp tục thông qua vụ tai nạn (w/trong Visual Studio)
  11. phương thức Close được gọi

Có một vài câu hỏi tôi đã:

  1. Tại sao Đóng gọi hai lần?
  2. Tại sao Flush được gọi sau khi Closed được gọi?
  3. Để điểm của Jay bên dưới, Có thể gọi hàm tuôn ra trước khi luồng hoàn toàn được đọc, vị trí logic bộ lọc nên ở đâu? Đóng? Trong Flush nhưng với "nếu đóng"?
  4. Triển khai đúng cách cho Bộ lọc phản hồi hoạt động trên toàn bộ nội dung cùng một lúc là gì?

Lưu ý: Tôi trải nghiệm cùng một hành vi (trừ các sự kiện đóng) nếu tôi không ghi đè phương thức Đóng.

public class ResponseFilter : MemoryStream 
{ 
    private readonly Stream _outputStream; 
    private MemoryStream _cachedStream = new MemoryStream(1024); 

    private readonly FilterBase _filter; 

    public ResponseFilter (Stream outputStream, FilterBase filter) 
    { 
     _outputStream = outputStream; 
     _filter = filter; 
    } 

    // Flush is called on the second, fourth, and so on, page request (second request) with empty content. 
    public override void Flush() 
    { 
     Encoding encoding = HttpContext.Current.Response.ContentEncoding; 

     string cachedContent = encoding.GetString(_cachedStream.ToArray()); 

     // Filter the cached content 
     cachedContent = _filter.Filter(cachedContent); 

     byte[] buffer = encoding.GetBytes(cachedContent); 
     _cachedStream = new MemoryStream(); 
     _cachedStream.Write(buffer, 0, buffer.Length); 

     // Write new content to stream 
     _outputStream.Write(_cachedStream.ToArray(), 0, (int)_cachedStream.Length); 
     _cachedStream.SetLength(0); 

     _outputStream.Flush(); 
    } 

    // Write is called on the first, third, and so on, page request. 
    public override void Write(byte[] buffer, int offset, int count) 
    { 
     // Cache the content. 
     _cachedStream.Write(buffer, 0, count); 
    } 

    public override void Close() 
    { 
     _outputStream.Close(); 
    } 
} 

// Example usage in a custom HTTP Module on the BeginRequest event. 
FilterBase transformFilter = new MapServiceJsonResponseFilter(); 
response.Filter = new ResponseFilter(response.Filter, transformFilter); 

Tài liệu tham khảo:

Trả lời

0

Flush không được gọi một cách rõ ràng. Có lẽ nó được gọi khi mã nhận ra một đối tượng mới là cần thiết, hoặc có lẽ là kết quả của một finalizer.

Tôi nghĩ rằng người ta có thể gọi tuôn ra sau khi viết bất kỳ gia tăng, vì vậy tôi không chắc chắn rằng một cuộc gọi để tuôn ra là một dấu hiệu đầy đủ của một tin nhắn hoàn chỉnh anyway.

+0

Thậm chí nếu được gọi ngầm là kết quả của trình kết thúc, tôi sẽ mong đợi _cachedContent chứa dữ liệu được ghi vào đó. Tuy nhiên, _cachedContent dường như không chứa dữ liệu. Điểm tốt về tuôn ra được sử dụng để viết gia tăng. –

7

Nhờ mẹo từ Jay về Flush được gọi là viết gia tăng tôi đã có thể làm cho Bộ lọc hoạt động như mong muốn bằng cách thực hiện logic lọc chỉ khi Bộ lọc đóng và chưa đóng. Điều này đảm bảo rằng Bộ lọc chỉ Flushes một lần khi Stream đang đóng. Tôi đã thực hiện điều này với một vài trường đơn giản, _isClosing và _isClosed như được hiển thị trong mã cuối cùng bên dưới.

public class ResponseFilter : MemoryStream 
{ 
    private readonly Stream _outputStream; 
    private MemoryStream _cachedStream = new MemoryStream(1024); 

    private readonly FilterBase _filter; 
    private bool _isClosing; 
    private bool _isClosed; 

    public ResponseFilter (Stream outputStream, FilterBase filter) 
    { 
     _outputStream = outputStream; 
     _filter = filter; 
    } 

    public override void Flush() 
    { 
     if (_isClosing && !_isClosed) 
     { 
      Encoding encoding = HttpContext.Current.Response.ContentEncoding; 

      string cachedContent = encoding.GetString(_cachedStream.ToArray()); 

      // Filter the cached content 
      cachedContent = _filter.Filter(cachedContent); 

      byte[] buffer = encoding.GetBytes(cachedContent); 
      _cachedStream = new MemoryStream(); 
      _cachedStream.Write(buffer, 0, buffer.Length); 

      // Write new content to stream 
      _outputStream.Write(_cachedStream.ToArray(), 0, (int)_cachedStream.Length); 
      _cachedStream.SetLength(0); 

      _outputStream.Flush(); 
     } 
    } 

    public override void Write(byte[] buffer, int offset, int count) 
    { 
     _cachedStream.Write(buffer, 0, count); 
    } 

    public override void Close() 
    { 
     _isClosing = true; 

     Flush(); 

     _isClosed = true; 
     _isClosing = false; 

     _outputStream.Close(); 
    } 
} 

Tôi chưa tìm thấy câu trả lời cho các câu hỏi khác ở trên để tôi sẽ không đánh dấu câu trả lời này là ngoại trừ tại thời điểm này.

+0

Điều này nên có được câu trả lời - nó đã giúp tôi thực hiện một bộ lọc đáp ứng bằng cách sử dụng HtmlAgilityPack để sửa đổi các thuộc tính trên các nút html. Cảm ơn bạn! –

+1

Tôi không hiểu lý do tại sao ghi đè phương thức Write bạn đặt luôn bằng 0 là offset? – Durden81

+1

+1. Và tôi quan tâm đến các lớp 'FilterBase' và' MapServiceJsonResponseFilter' của bạn ... – jerone

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