Programming Microsoft ASP.NET 4 - Dino Esposito [341]
In ASP.NET, all caching capabilities are grouped in the HttpCachePolicy class. With regard to page caching, the class has a double role. It provides methods for both setting cache-specific HTTP headers and controlling the ASP.NET page output cache. In this chapter, we’re mostly interested in the HTTP headers, and we’ll keep page output caching warm for Chapter 18.
To set the visibility of a page in a client cache, use the SetCacheability method of the HttpCachePolicy class. To set an expiration time, use the SetExpires method, which takes for input an absolute DateTime object. Finally, to set a lifetime for the cached page, pass to SetExpires the current time plus the desired interval.
Note
In the case of conflicting cache policies, ASP.NET maintains the most restrictive settings. For example, if a page contains two controls that set the Cache-Control header to public and private, the most restrictive policy will be used. In this case, Cache-Control: Private is what will be sent to the client.
Setting an Output Filter
In ASP.NET, a new component makes its debut—the response filter. A response filter is a Stream-derived object associated with the HttpResponse object. It monitors and filters any output being generated by the page. If you set the Filter property with the instance of a class derived from Stream, all output being written to the underlying HTTP writer first passes through your output filter.
The custom filter, if any, is invoked during the HttpResponse’s Flush method before the actual text is flushed to the client. An output filter is useful for applying the final touches to the markup, and it is sometimes used to compact or fix the markup generated by controls.
Building a response filter is a matter of creating a new stream class and overriding some of the methods. The class should have a constructor that accepts a Stream object. In light of this, a response filter class is more a wrapper stream class than a purely inherited stream class. If you simply try to set Response.Filter with a new instance of, say, MemoryStream or FileStream, an exception is thrown.
The following listing shows how to create a stream class that works as a response filter. For simplicity, the class inherits from MemoryStream. You might want to make it inherit from Stream, but in this case you need to override (because they are abstract) a number of methods, such as CanRead, CanWrite, CanSeek, and Read. The class converts lowercase characters to uppercase ones.
public class MyFilterStream : MemoryStream
{
private Stream m_Stream;
public MyFilterStream(Stream filterStream)
{
m_Stream = filterStream;
}
// The Write method actually does the filtering
public override void Write(byte[] buffer, int offset, int count)
{
// Grab the output as a string
string buf = UTF8Encoding.UTF8.GetString(buffer, offset, count);
// Apply some changes
// Change lowercase chars to uppercase
buf = buf.ToUpper();
// Write the resulting string back to the response stream
byte[] data = UTF8Encoding.UTF8.GetBytes(buf.ToString());
m_Stream.Write(data, 0, data.Length);
}
}
Use the following code to associate this output filter with the Response.Filter property. Here’s a sample page:
void Page_Load(object sender, EventArgs e)
{
Response.Filter = new MyFilterStream(Response.Filter);