Hugoware

The product of a web developer with a little too much caffeine

Archive for May 9th, 2009

Free Bandwidth For All ASP.NET Users

with 7 comments

That’s right, you read it correctly – free bandwidth. With a very short function we’re going to minify our output.

Makes me think of a song, but I don’t want to ruin the rest of the post.

When people render their WebForms and MVC Views, they send their finished HTML back down to the page. The HTML contains all the markup required to run in the browser. Every developer knows all this though (and if not… well…).

Part of the whole grand ASP.NET pipeline is the Response.Filter. A seemingly innocent property with a lot of potential. Enough boasting about this guy, let’s get onto the code and see what it can do.

First, you’re going to need to create a custom stream. I’m hiding all the inherited members because they aren’t going to mean much in this example, but don’t forget that you need them.

With our custom stream, add a hidden property called the UnderlyingStream (honestly call it whatever you want). Lastly, accept a stream in the constructor and assign it to the underlying stream when you instantiate the new stream you’re building.

Lastly, we’re going to override .Write() routine to actually minify our output. A couple simple Regular Expressions and we can chop out most of the whitespace.

public class MinifyFilter : Stream {

//inherited members from Stream class – Don’t forget
//See download for more information
//…

//The real output stream
private Stream _UnderlyingStream;

//Make sure to pass in the current Response.Filter
public MinifyFilter(Stream stream) {
this._UnderlyingStream = stream;
}

//Override our write event
public override void Write(byte[] buffer, int offset, int count) {

//clean out the whitespace characters
string html = Encoding.UTF8.GetString(buffer);
html = Regex.Replace(html, @”\n|\t”, ” “);
html = Regex.Replace(html, @”>\s+<", "><").Trim(); html = Regex.Replace(html, @"\s{2,}", " "); //write the new html byte[] output = Encoding.UTF8.GetBytes(html); this._UnderlyingStream.Write(output, 0, output.Length); } } [/sourcecode] This is a very streamlined version of the code that doesn't take everything into account. You might want to put some special attention into preventing formatting of text in the <pre> tags or <code> tags, but it's a great start. Now using it is as simple as... [sourcecode language='csharp'] //MVC Example: At the start of a controller action public ActionResult Index() { this.Response.Filter = new MinifyFilter(this.Response.Filter); //...rest of the action return this.View();  } //WebForms Example: At the Page_Init protected void Page_Init(object sender, EventArgs e) { this.Response.Filter = new MinifyFilter(this.Response.Filter); //rest of the Page_Init code } [/sourcecode] You could also assign this to a more global event that runs for all requests, but at that point you will need to write code to make sure you don't accidentally minify something like an image or a file (things that can't be compressed by just removing white-spaces). You might wonder how much a little script like this would save. The answer is simple - It depends. Clearly, pages with a lot of white spaces will find a lot more gain. Sometimes it’s 1 or 2 KBs (which will add up over the course of a month). Sometimes though, especially on larger pages, you can see some real savings.

Here are a few popular sites and their savings

GameSpy 94K – (84K minified)

StackOverflow 119K – (102K minified)

Forums.ASP.net 222K – (154K minified)

Keep in mind that this code isn’t bullet-proof, but instead it’s here to get you started. You can continue to tweak the .Write() method to make sure that your code behaves the way you would like.

With all the savings you get from the extra bandwidth make sure you remember to send me a Coke Zero!

Source Code

Download MinifyFilter.cs

.

Written by hugoware

May 9, 2009 at 4:50 am