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:
- Yêu cầu đầu tiên
- Viết phương pháp được gọi là
- phương pháp Flush được gọi
- phương thức Close được gọi
- phương thức Close được gọi là
- Tại thời điểm này, ứng dụng trả về và nội dung phù hợp được hiển thị.
- Yêu cầu thứ hai
- phương pháp được gọi là Flush
- ứng dụng bị treo trên _outputStream.Write. ArgumentOutOfRangeException (offset).
- Tiếp tục thông qua vụ tai nạn (w/trong Visual Studio)
- phương thức Close được gọi
Có một vài câu hỏi tôi đã:
- Tại sao Đóng gọi hai lần?
- Tại sao Flush được gọi sau khi Closed được gọi?
- Để đ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"?
- 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:
- How do I deploy a managed HTTP Module Site Wide?
- Creating multiple (15+) HTTP Response filters, Inheritance vs. Composition w/ Injection
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. –