May 2009 Blog Posts
ASP.NET Pages are designed to stream their output directly to a response stream. This can be a huge performance benefit for large pages as it doesn’t require buffering and allocating very large strings before rendering. Allocating large strings can put them on the Large Object Heap which means they’ll be sticking around for a while.
However, there are many cases in which you really want to render a page to a string so you can perform some post processing. I wrote about one means using a Response filter eons ago.
However, recently, I learned about a method of the Page class I never noticed which allows me to use a much lighter weight approach to this problem.
The method in question is CreateHtmlTextWriter which is protected, but also virtual.
So here’s an example of the code-behind for a page that can leverage this method to filter the output before its sent to the browser.
public partial class FilterDemo : System.Web.UI.Page
{
HtmlTextWriter _oldWriter = null;
StringWriter _stringWriter = new StringWriter();
protected override HtmlTextWriter CreateHtmlTextWriter(TextWriter tw)
{
_oldWriter = base.CreateHtmlTextWriter(tw);
return base.CreateHtmlTextWriter(_stringWriter);
}
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
string html = _stringWriter.ToString();
html = html.Replace("REPLACE ME!", "IT WAS REPLACED!");
_oldWriter.Write(html);
}
}
In the CreateHtmlTextWriter method, we simply use the original logic to create the HtmlTextWriter and store it away in an instance variable.
Then we use the same logic to create a new HtmlTextWriter, but this one has our own StringWriter as the underlying TextWriter. The HtmlTextWriter passed into the Render method is the one we created. We call Render on that and grab the output from the StringWriter and now can do all the replacements we want. We finally write the final output to the original HtmlTextWriter which is hooked up to the response.
A lot of caveats apply in using this technique. First, as I mentioned before, for large pages, you could be killing scalability and performance by doing this. Also, I haven’t tested this with output caching, async pages, etc… etc…, so your mileage may vary.
Note, if you want to call one page from another, and get the output as a string within the first page, you can pass your own TextWriter to Server.Execute, so this technique is not necessary in that case.
Being that it’s a glorious Memorial Day Weekend up here in the Northwest, my co-worker Eilon (developer lead for ASP.NET MVC) and I decided to go on a hike to Mt Si where we had a bit of a scary moment.
I first learned about Mt Si at the company picnic last year, seen behind me and Cody in this photo. I remember seeing the imposing cliff face and thinking to myself, I want to climb up there. I imagined the view would be quite impressive.
Mt Si is a moderately strenuous hike 8 miles round trip with an elevation gain of 3100 feet taking you to about 3600 feet, according to the Washington Trails Association website. Given that it is a very popular hike and that this was a three-day weekend, we figured we’d get an early start by heading over there at 7 AM.
That ended up being a good idea as the parking lot had quite a few cars already, but it wasn’t full by any means. This is a picture of the trail head which starts the hike off under a nice canopy of green.
Right away, the no-nonsense trail starts you off huffing uphill amongst a multitude of trees.
Along the way, there are the occasional diversions. For example, this one won me $10 as the result of a bet that I wouldn’t walk to the edge of the tree overhanging the drop off.
When you get to the top, there’s a great lookout with amazing views. But what caught our attention is a rock outcropping called the “Haystack”, which takes you up another 500 feet. Near the base of the Haystack is a small memorial for those who’ve died from plummeting off its rocky face. It’s not a trivial undertaking, but I demanded we try.
Unfortunately, there’s nothing in the above picture to provide a better sense of scale for this scramble. In the following picture you can see some people pretty much scooting down the steep slope on their butts.
Once they were down, we set up and reached around two thirds of the way when I made the mistake of looking back and made a remark about how it’s going to be much more difficult going down. That started getting us nervous because it’s always easier going up than down.
It would have probably been best if I hadn’t made that remark because the climb wasn’t really that difficult, but introducing a bit of nervousness into the mix can really sabotage one’s confidence, which you definitely want on a climb.
At that point, the damage was done and we decided we had enough and started heading back down. Better to try again another day when we felt more confident. At that moment, a couple heading down told us we were almost there and it wasn’t so bad. Our success heading back down and their comments started to bolster our confidence to the point where I was ready to head back up, until I noticed that my shoe felt odd.
What I hadn’t noticed while climbing on the steep face was that my sole had almost completely detached from my hiking boot during the climb. Fortunately, Eilon had some duct tape on hand allowing me to make this ghetto looking patch job.
At this point I had a mild panic because I worried that the duct tape would cause me to lose grip with my boots on the way down. And frankly, I was pissed off as well, as I’ve had these boots for a few years, but haven’t hiked in them all that often. What a perfect time for them completely fall apart!
Fortunately, I didn’t have much problem climbing back down and we stopped at the first summit to take some pictures and have a brief snack.
Not having the guts today to climb the big rock, I scrambled up a much smaller one and got this great view of Mt Rainier in its full splendor.
The view from the top is quite scenic and using binoculars, I was able to check on my family back in Bellevue (joke).
Going back down was much quicker than the way up and we had a blast of it practically trail running the first part, until my other shoe gave out.
Guess the warranty must have run out yesterday. ;) Fortunately, Eilon, who was prepared with the Duct tape, also had all terrain sandals with him, which I wore the rest of the way. Next time, I think I’ll ditch the Salomon boots and try Merrells which other hikers I ran into were wearing.
Despite the mishaps, the hike was really a fun romp in the woods and I highly recommend it to anyone in the Seattle area to give it a try. Go early to avoid the crowds. I doubled my $10 in an over/under bet where I took 140 and over cars in the lot. We stopped counting at around 170 cars in the lot when we left.
This is one last look at Mt Si on our way back home. Eilon put together a play-by-play using Live Maps Bird’s Eye view (click for larger).
For more info on the Mt Si hike, check out the Washington Trails Association website.
This post is now outdated
I apologize for not blogging this over the weekend as I had planned, but the weather this weekend was just fantastic so I spent a lot of time outside with my son.
If you haven’t heard yet, Visual Studio 2010 Beta 1 is now available for MSDN subscribers to download. It will be more generally available on Wednesday, according to Soma.
You can find a great whitepaper which describes what is new for web developers in ASP 4 which is included.
One thing you’ll notice is that ASP.NET MVC is not included in Beta 1. The reason for this is that Beta 1 started locking down before MVC 1.0 shipped. ASP.NET MVC will be included as part of the package in VS10 Beta 2.
Right now, if you try and open an MVC project with VS 2010 Beta 1, you’ll get some error message about the project type not being supported. The easy fix for now is to remove the ASP.NET MVC ProjectTypeGuid entry as described by this post.
We’re working hard to have an out-of-band installer which will install the project templates and tooling for ASP.NET MVC which works with VS2010 Beta 1 sometime in June on CodePlex. Sorry for the inconvenience. I’ll blog about it once it is ready.
A while back, I wrote about Donut Caching in ASP.NET MVC for the scenario where you want to cache an entire view except for a small bit of it. The more technical term for this technique is probably “cache substitution” as it makes use of the Response.WriteSubstitution method, but I think “Donut Caching” really describes it well — you want to cache everything but the hole in the middle.
However, what happens when you want to do the inverse. Suppose you want to cache the donut hole, instead of the donut?

I think we should nickname all of our software concepts after tasty food items, don’t you agree?
In other words, suppose you want to cache a portion of the view in a different manner (for example, with a different duration) than the entire view? It hasn’t been exactly clear how do to do this with ASP.NET MVC.
For example, the Html.RenderPartial method ignores any OutputCache directives on the view user control. If you happen to use Html.RenderAction from MVC Futures which attempts to render the output from an action inline within another view, you might run into this bug in which the entire view is cached if the target action has an OutputCacheAttribute applied.
I did a little digging into this today and it turns out that when you specify the OutputCache directive on a control (or page for that matter), the output caching is not handled by the control itself. Rather, it appears that compilation system for ASP.NET pages kicks in and interprets that directive and does the necessary gymnastics to make it work.
In plain English, this means that what I’m about to show you will only work for the default WebFormViewEngine, though I have some ideas on how to get it to work for all view engines. I just need to chat with the members of the ASP.NET team who really understand the deep grisly guts of ASP.NET to figure it out exactly.
With the default WebFormViewEngine, it’s actually pretty easy to get partial output cache working. Simply add a ViewUserControl declaratively to a view and put your call to RenderAction or RenderPartial inside of that ViewUserControl. If you’re using RenderAction, you’ll need to remove the OutputCache attribute from the action you’re pointing to.
Keep in mind that ViewUserControls inherit the ViewData of the view they’re in. So if you’re using a strongly typed view, just make the generic type argument for ViewUserControl have the same type as the page.
If that last paragraph didn’t make sense to you, perhaps an example is in order. Suppose you have the following controller action.
public ActionResult Index() {
var jokes = new[] {
new Joke {Title = "Two cannibals are eating a clown"},
new Joke {Title = "One turns to the other and asks"},
new Joke {Title = "Does this taste funny to you?"}
};
return View(jokes);
}
And suppose you want to produce a list of jokes in the view. Normally, you’d create a strongly typed view and within that view, you’d iterate over the model and print out the joke titles.
We’ll still create that strongly typed view, but that view will contain a view user control in place of where we would have had the code to iterate the model (note that I omitted the namespaces within the Inherits attribute value for brevity).
<%@ Page Language="C#" Inherits="ViewPage<IEnumerable<Joke>>" %>
<%@ Register Src="~/Views/Home/Partial.ascx" TagPrefix="mvc" TagName="Partial"
%>
<mvc:Partial runat="server" />
Within that control, we do what we would have done in the main view and we specify the output cache values. Note that the ViewUserControl is generically typed with the same type argument that the view is, IEnumerable<Joke>. This allows us to move the exact code we would have had in the view to this control. We also specify the OutputCache directive here.
<%@ Control Language="C#" Inherits="ViewUserControl<IEnumerable<Joke>>" %>
<%@ OutputCache Duration="10000" VaryByParam="none" %>
<ul>
<% foreach(var joke in Model) { %>
<li><%= Html.Encode(joke.Title) %></li>
<% } %>
</ul>
Now, this portion of the view will be cached, while the rest of your view will continue to not be cached. Within this view user control, you could have calls to RenderPartial and RenderAction to your heart’s content.
Note that if you are trying to cache the result of RenderPartial this technique doesn’t buy you much unless the cost to render that partial is expensive.
Since the output caching doesn’t happen until the view rendering phase, if the view data intended for the partial view is costly to put together, then you haven’t really saved much because the action method which provides the data to the partial view will run on every request and thus recreate the partial view data each time.
In that case, you want to hand cache the data for the partial view so you don’t have to recreate it each time. One crazy idea we might consider (thinking out loud here) is to allow associating output cache metadata to some bit of view data. That way, you could create a bit of view data specifically for a partial view and the partial view would automatically output cache itself based on that view data.
This would have to work in tandem with some means to specify that the bit of view data intended for the partial view is only recreated when the output cache is expired for that partial view, so we don’t incur the cost of creating it on every request.
In the RenderAction case, you really do get all the benefits of output caching because the action method you are rendering inline won’t get called from the view if the ViewUserControl is outputcached.
I’ve put together a small demo which demonstrates this concept in case the instructions here are not clear enough. Enjoy!
A while back a young developer emailed me asking for advice on what it takes to become a successful developer. I started to respond,
I don’t know. Why don’t you go ask a successful developer?
But then I thought, that’s kind of snarky, isn’t it? And who am I kidding with all that false modesty? After all, the concept of a “clever hack” was named after me, but the person who came up with it didn’t have 1/10 of my awesomeness which is exceedingly apparent given the off-by-one error that dropped one of the “a”s from the phrase when it was coined. This, of course, was all before I invented TDD, the Internet, and breathing air.
(note to the humor impaired, I didn’t really invent TDD)
But as I’m apt to do, I digress…
I started thinking about the question a bit and said to myself, “If I were a successful developer, what would have I done to become that?” As I started brainstorming ideas, one thing that really stood out was joining an open source project.
If one thing in my career has paid dividends, it was getting involved with open source projects. It exposed me to such a diverse set of problems and technologies that I wouldn’t normally get a chance to work on at work.
Now before I go further, this post is not the post where I answer the young developer’s question. No, that’s a post for another time. I’ll probably give it some trite and pompous title like “Advice for a young developer.” I mean, c’mon! How pathetic and self absorbed is that title? “Get over yourself!” I’ll say to the mirror. But the guy in the mirror will probably do it anyways, but in reverse.
No, this is not that post. Rather, this post is a digression from that post, because if I’m good at one thing, it’s digressing.
As I thought about the open source thing, I got to thinking about the first open source project I ever worked on – RSS Bandit (w00t w00t!). RSS Bandit is a kick butt RSS aggregator developed by Dare Obasanjo and Torsten Rendelmann. I had just started to get into blogging at the time and was really impressed by Dare’s outspoken and yet very thoughtful blog as well as by his baby at the time, RSS Bandit (he has a real baby now, congrats man!).
I hadn’t done much Windows client development back then. I was mostly building web applications in classic ASP and then early versions of ASP.NET. I figured that it would be exciting to cut my teeth on RSS Bandit and learn Winforms development in the process. The idea of a stateful programming model had me positively giddy with excitement. This was going to be so cool.
Many new developers approaching an open source project have grand visions of implementing shiny amazing new features that will have the crowds roaring, the President naming a holiday after you, and all your enemies realizing the errors of their ways and naming their children after you.
But a good contributor swallows his or her pride and starts off slowly with something smaller in scope, and more grunt work like in nature. Most OSS projects have a real need for documentation, partly because all the glamour is in implementing features so nobody wants to write the documentation.
That’s where I started. I wrote an article for the docs, getting started with RSS Bandit. Dare took a notice and asked if I would contribute to the documentation, which I gladly agreed to do. He gave me commit access (I believe I was the third after Dare and Torsten to get commit rights) and started working very hard on the documentation. In fact, much of what I wrote is still there as you can see in my narcissistic application screenshots I used. ;)
Over time, I gained more and more trust and was allowed to work on some bug fixes and features. My first main feature was implementing configurable keyboard shortcuts, which was really neat to implement.
(A bit of trivia. I worked with these guys for years on RSS Bandit, but never met Dare in person until this past Mix conference in Las Vegas. Seriously! I’ve yet to meet Torsten who lives in Germany.)
I really loved working on RSS Bandit and it became quite a hobby that took up what little was left of my free time. I guess you could say it kept me out of gangs in the hard streets of Los Angeles, not that I tried to join nor would they accept me. Over time though, I learned something. Despite all that initial giddiness over finally getting to program in a stateful environment…
I realized I didn’t like it.
In fact, I found it quite foreign and challenging. I kept running into weird problems where controls still had the state they had before after a user clicked a button. I would think to myself, “why do I have to clear that state myself? Why doesn’t it just go away when the user takes an action?” I realized my problem was that I was thinking like a web programmer, not a client programmer who took these things for granted.
As challenging as a client programmer finds the web, where you have to recreate the state on each request because the web is stateless, a developer who primarily programs the web sometimes finds client development challenging because the state is like that ugly sidekick next to the hot one at a bar -- it…just…won’t…go…away.
I realized then, that I’m just a web developer at heart and I’d rather make web, not war. It was around that time that I started the Subtext project where I felt more in my element working on a web application. Eventually, I stopped using RSS Bandit preferring a web based solution in Google Reader, ironically, because the state of my feeds is always there, in the cloud, without me needing to synchronize or install an app when I’m at a new computer.
So while I actually like (or maybe am just accustomed to) the stateless programming model of the web, I’m also attracted to the statefulness of web applications as a whole in that the state of my data is not tied to any one machine but it’s stored centrally where I can easily get to it from anywhere (which yes, has its own concerns and problems such as when the net is down).
At the same time, I do check in now and then to see how RSS Bandit is progressing. There are very cool features that it has that I miss out on with Google Reader such as the ability to comment directly from the aggregator via the Comment API and the ability to subscribe to authenticated feeds. And I think Dare’s taking RSS Bandit into compelling new directions.
All this is to say that if you want to become a better developer, join an open source project (such as this one :) because it might just show you exactly what type of developer you are at heart. As I learned, I’m a web developer at heart.
As I’m sure you know, we developers are very particular people and we like to have things exactly our way. How else can you explain long winded impassioned debates over curly brace placement?
So it comes as no surprise that developers really care about what goes in (and behind) their .aspx files, whether they be pages in Web Forms or views in ASP.NET MVC.
For example, some developers are adamant that a page should not include server side script blocks, while others don’t want their views to contain Web Form controls. Wouldn’t it be great if you could have your views reject such code constructs?
Fortunately, ASP.NET is full of lesser known extensibility gems which can help in such situations such as the PageParseFilter. MSDN describes this class as such:
Provides an abstract base class for a page parser filter that is used by the ASP.NET parser to determine whether an item is allowed in the page at parse time.
In other words, implementing this class allows you to go along for the ride as the page parser parses the .aspx file and gives you a chance to hook into that parsing.
For example, here’s a very simple filter which blocks any script tags with the runat="server" attribute set within a page.
using System;
using System.Web.UI;
public class MyPageParserFilter : PageParserFilter {
public override bool ProcessCodeConstruct(CodeConstructType codeType
, string code) {
if (codeType == CodeConstructType.ScriptTag) {
throw new InvalidOperationException("Say NO to server script blocks!");
}
return base.ProcessCodeConstruct(codeType, code);
}
public override bool AllowCode {
get {
return true;
}
}
public override bool AllowControl(Type controlType, ControlBuilder builder)
{
return true;
}
public override bool AllowBaseType(Type baseType) {
return true;
}
public override bool AllowServerSideInclude(string includeVirtualPath) {
return true;
}
public override bool AllowVirtualReference(string referenceVirtualPath
, VirtualReferenceType referenceType) {
return true;
}
public override int NumberOfControlsAllowed {
get {
return -1;
}
}
public override int NumberOfDirectDependenciesAllowed {
get {
return -1;
}
}
}
Notice that we had to override some defaults for other properties we’re not interested in such as NumberOfControlsAllowed or we’d get the default of 0 which is not what we want in this case.
To apply this filter, just specify it in the <pages /> section of web.config like so:
<pages
pageParserFilterType="Namespace.MyPageParserFilter, AssemblyName">
Applying a parse filter for Views in ASP.NET MVC is a bit trickier because it already has a parse filter registered, ViewTypeParserFilter, which handles part of the voodoo black magic in order to remove the need for code-behind in views when using a generic model type. Remember those particular developers I was talking about?
Suppose we want to prevent developers from using server controls which make no sense in the context of an ASP.NET MVC view. Ideally, we could simply inherit from ViewTypeParserFilter and make our change so we don’t lose the existing view functionality.
That type is internal so we can’t simply inherit it. Fortunately, what we can do is simply grab the ASP.NET MVC source code for that type, rename the type and namespace, and then change it to meet our needs. Once we’re done, we can even share those changes with others. This is one of the benefits of having an open source license for ASP.NET MVC.
WARNING: The fact that we implement a ViewTypeParserFilter is an implementation detail. The goal is that in the future, we wouldn’t need this filter to provide the nice generic syntax. So what I’m about to show you might be made obsolete in the future and should be done at your own risk. It’s definitely running with scissors.
In my demo, I copied the following files to my project:
I then created a new parser filter which inherits the ViewTypeParserFilter and overrode the AllowControl method like so:
public override bool AllowControl(Type controlType, ControlBuilder builder) {
return (controlType == typeof(HtmlHead)
|| controlType == typeof(HtmlTitle)
|| controlType == typeof(ContentPlaceHolder)
|| controlType == typeof(Content)
|| controlType == typeof(HtmlLink));
}
This will block adding any control except for those necessary in creating a typical view. You can imagine later adding some easy way of configuring that list in case you do later allow other controls.
Once we’ve implemented this new filter, we can edit the Web.config file within the Views directory to set the parser filter to this one.
This is a powerful tool for hooking into the parsing of a web page, so do be careful with it. As you might expect, I have a very simple demo of this feature here.