Thursday, April 12, 2012

T4MVC has its own home, with some git love

I have just moved T4MVC to a new CodePlex project, instead of it being part of the MvcContrib project. Its new home is https://t4mvc.codeplex.com/.

If you’re a T4MVC user, that should not make much difference except that there is now a new place to discuss it and file bugs. NuGet is still the place to go to get T4MVC!

Note that T4MVC is still part of the MvcContrib effort, even if it doesn’t share the same source tree. Here are the reasons for the move.

Reduce confusion

T4MVC is quite separate from the rest of MvcContrib, because it’s just a T4 template, and not some code that’s part of an assembly. Having the T4MVC files be in their own little island in the middle of a repo with many unrelated thing has been a bit of a barrier of entry for people wanting to make a quite contribution.

Also, since all MvcContrib bugs are files in the same place, there was always additional pain for me to filter T4MVC issues from unrelated ones.

Likewise, we’ll now have our own discussion forum that only focuses on T4MVC. Most users have been using StackOverflow for T4MVC support, and you can continue to do that if you prefer.

Switch to git!

I’ve been increasingly using git over Mercurial (like everyone else it seems!), to the point where having to use Mercurial is becoming an annoyance. Since CodePlex now supports git, it was the perfect opportunity to switch to that!

Monday, February 13, 2012

Quick fun with Mono’s CSharp compiler as a service

Mono comes with a really cool CSharp compiler as a service. The only problem is that no one seems to know about it!

I think the main reason for this is that anything related to Mono causes a fair bit of confusion to all the people who are not familiar with it. And that certainly includes myself, as I know very little about it besides what I’m discussing in this post!

Talking to various people, the general misconceptions are:

  • Mono only runs on Linux
  • Even if it runs on Windows, it doesn’t use the CLR, so I can’t use it
  • Mono is for strange people :)

And while that may be true for some aspects of Mono, it certainly isn’t for Mono.CSharp.dll. In fact, it’s a totally ‘normal’ library that you can use in your very ‘normal’ C# projects in Visual Studio.

The next hurdle is that it’s not all that easy to just get Mono.CSharp.dll. You have to either install an 80MB setup from here, or get a big .tar.gz file with lots of other things from here. And a lot of people on Windows don’t like dealing with tar.gz files (hint: use 7zip).

Now the good news: after chatting with Miguel de Icaza on Twitter, I put Mono.CSharp.dll on NuGet, making it totally trivial to use from VS. There goes that hurdle. (note: I’m the package owner for now, until some Miguel-blessed dev claims it).

Try Mono.CSharp in under 5 minutes

Just open VS and create a Console app, and add a NuGet package reference to Mono.CSharp. That takes a whole 30 seconds. And I’ll re-emphasize that there is nothing ‘Mono’ about this Console app. It’s just plain vanilla.

Now write some basic code to use the compiler. It all revolves around the Evaluator class. Here is the sample code I used (GitHub). It’s quick and dirty with poor error handling, as the focus is to just demonstrate the basic calls that make things work:

using System;
using System.IO;
using Mono.CSharp;

namespace MonoCompilerDemo
{
    public interface IFoo { string Bar(string s); }

    class Program
    {
        static void Main(string[] args)
        {
            var evaluator = new Evaluator(
                new CompilerSettings(),
                new Report(new ConsoleReportPrinter()));

            // Make it reference our own assembly so it can use IFoo
            evaluator.ReferenceAssembly(typeof(IFoo).Assembly);

            // Feed it some code
            evaluator.Compile(
                @"
    public class Foo : MonoCompilerDemo.IFoo
    {
        public string Bar(string s) { return s.ToUpper(); }
    }");

            for (; ; )
            {
                string line = Console.ReadLine();
                if (line == null) break;

                object result;
                bool result_set;
                evaluator.Evaluate(line, out result, out result_set);
                if (result_set) Console.WriteLine(result);
            }
        }
    }
}

It feeds it some starter code and start a REPL look to evaluate expressions. e.g. run it and try this. You type the first two, and the 3rd is output:

MonoCompilerDemo.IFoo foo = new Foo();
foo.Bar("Hello Mono.CSharp");
HELLO MONO.CSHARP

You get the idea!

What about Roslyn?

I blogged a few months back about using Roslyn to implement an MVC Razor view engine. I’m far from a Roslyn expert, and frankly haven’t done much with it since that post. From what I read, Roslyn has the potential to enable some very compelling scenarios in the future.

But there is one major argument right now in favor of using the Mono compiler: it’s pretty much feature complete today, while Roslyn is not even close. Totally understandable given that it’s a CTP, and is only meant to give an early taste of the feature.

So anyway, I still know close to nothing about Mono, but if I need to dynamically compile some pieces of C# in a ‘normal’ non-Mono project, I know that Mono.CSharp is not far away!

Wednesday, October 19, 2011

Using Roslyn to implement an MVC Razor view engine

Update 12/29/2011: the Roslyn CTP is now available on NuGet, so it's no longer necessary to install it before running this sample!

Note: the code for this view engine sample is on Github.

The C# team has just announced the public availability of the first Roslyn CTP. See their post here, and download it from here. I really hope they can make it available on NuGet soon, but right now it’s not there, so you’ll have to run their setup. Sorry!

As you’ve probably heard from various conferences earlier this year, Roslyn offers a compiler as a service for C# and VB. Since we do a lot of compilation in ASP.NET land, I figured I’d play around with trying write an MVC view engine that uses it instead of the standard compilation path.

Word of warning: the Roslyn CTP is still very rough and is missing a lot of key features, like dynamic, anonymous types, indexers and using statements (get the full list here). So while I did get something working, the language limitations prevent it from being useful in any real scenario. This is just an exercise to see how far we can get. Lower your expectations! :)

Why would we want to do this

When you have a standard MVC project, compilation happens at two different levels:

  • Your Controllers, Models, and most of your C# code get compiled by msbuild (or Visual Studio) into a single assembly which ends up in the ‘bin’ folder
  • All the Views (whether .aspx or .cshtml) get compiled dynamically at runtime by ASP.NET.

One drawback of compiling views at runtime is that it’s pretty slow. And since it’s slow, ASP.NET tries really hard to save assemblies to disk so it can reuse them across AppDomain cycles. Those assemblies all go under the infamous ‘Temporary ASP.NET Files’ folder. There is a huge amount of complexity to make this work, with settings like batching which can either help or hurt depending on the situation.

One thing I’ve been working on to avoid this dynamic compilation is RazorGenerator, which lets you precompile your views into the same assembly as your controllers. This works quite nicely, but it does have one big drawback: you can’t just update a view and have it get picked up at runtime. Instead, you need to rebuild using msbuild (or VS), just like you would when you change a controller file.

What would be nice is to be able to support dynamic compilation of the views, but with a much lighter system then what the standard ASP.NET Build Manager provides. Enter Roslyn!

Compile views using Roslyn: fast and lightweight

The main reason that the standard build manager is pretty slow is that it goes through CodeDom, which launching csc.exe for every compilation. csc.exe is actually very fast at compiling C# code, but the fact that we have to pay for the csc process startup time each time we compile anything ends up making things slow.

By contrast, Roslyn gives us an API to compile code in memory, without ever having to launch another process, making things much faster. In fact, it is so fast that the incentive that we had to preserve compiled assembly in ‘Temporary ASP.NET Files’ mostly disappears.

Instead, we can take a much simpler approach: whenever we need to compile a view, we just compile it on the fly in memory using Roslyn, and then cache it for the lifetime of the AppDomain. But we never need to cache it to disk, and generally don’t use the disk at all.

In preliminary tests, I have measured the perf of compiling pages using Roslyn to be more than 50 times faster than doing it via CodeDom. So it’s looking quite promising!

So to summarize, the benefits of using Roslyn to implement a view engine are:

  • Fast dynamic compilation
  • No need to cache assemblies to disk, leading to a much simpler and lighter weight system.
  • New shiny thing! :)

More detail about the code

The code for my sample view engine is on Github (https://github.com/davidebbo/RoslynRazorViewEngine), so I’ll mostly let you check it out there. All the interesting code is in RoslynRazorViewEngine.cs.

Here are the main steps that it goes through to turn a Razor file into an Assembly:

  1. First it uses the Razor Engine to generate a CodeCompileUnit from the Razor file.
  2. It then uses CodeDom to turn the CodeCompileUnit into C# source code. Note that we only use CodeDom as a code generator here, and not to actually compile anything.
  3. We then use Roslyn to compile the course code into a byte[]. That byte array is basically an in memory copy of what would normally be a .dll file.
  4. Finally, we call Assembly.Load to load that byte[] into a runtime Assembly.

How restrictive are the limitations in the Roslyn CTP?

As I mentioned above, there are lots of limitations, which make this little more than a proof of concept.

To begin with, it doesn’t support dynamic, which MVC uses pretty heavily. By default, MVC views extend WebViewPage<dynamic>, so I had to add ‘@model object’ at the top of my test view to get around that.

Then there is ViewBag, which is also dynamic, and allows writing things like ‘@ViewBag.Message’. I tried replacing that by ‘@ViewData["Message"]’, only to find out that indexers were not supported either. Duh!

And then it doesn’t support anonymous objects, which MVC uses quite a bit...

So don’t even think of trying to use this for anything real at this time. Still, the approach feels pretty sound, and whenever Roslyn becomes more feature complete, I have good hope that it can help us improve the ASP.NET compilation system.

Tuesday, August 16, 2011

The easy way to set up NuGet to restore packages

Note (12/22/2011): in NuGet 1.6 or later, this feature is built in, so you no longer need to use the NuGetPowerTools. Just right click on the Solution and choose 'Enable NuGet Package Restore'.

A few months ago, I described a workflow that lets you use NuGet without committing the packages to source control. This has been a very popular workflow, and generally works quite well.

The down side is that it’s a bit painful to set up: you have to get NuGet.exe and add it to your tree, then you have to add a pre-build event for every project that uses NuGet.

The good news is that the ever-resourceful David Fowler has come up with a much easier way to set that up, using his NuGetPowerTools package. Here is the way to do it:

Let’s assume that you have a solution that is either already using NuGet, or planning to use it, and that you want to set up the no-commit workflow.

Now, you just need to go to the Package Manager Console and run a couple commands:

PM> Install-Package NuGetPowerTools
Successfully installed 'NuGetPowerTools 0.28'.

**********************************************************************************
INSTRUCTIONS
**********************************************************************************
- To enable building a package from a project use the Enable-PackageBuild command
- To enable restoring packages on build use the Enable-PackageRestore command.
- When using one of the above commands, a .nuget folder will been added to your
solution root. Make sure you check it in!
- For for information, see https://github.com/davidfowl/NuGetPowerTools
**********************************************************************************


PM> Enable-PackageRestore
Attempting to resolve dependency 'NuGet.CommandLine (≥ 1.4)'.
Successfully installed 'NuGet.CommandLine 1.4.20615.182'.
Successfully installed 'NuGet.Build 0.16'.

Copying nuget.exe and msbuild scripts to D:\Code\StarterApps\Mvc3Application\.nuget
Successfully uninstalled 'NuGet.Build 0.16'.
Successfully uninstalled 'NuGet.CommandLine 1.4.20615.182'.

Don't forget to commit the .nuget folder
Updated 'Mvc3Application' to use 'NuGet.targets'
Enabled package restore for Mvc3Application

And you’re done! So basically, the first command installs a NuGet package which brings in some helpful commands, and the second one runs one of those commands.

After doing this, you’ll notice a new .nuget folder under your solution, containing nuget.exe plus a couple msbuild target files. Make sure you commit that folder to source control! You’ll also find a few changes in your csproj files to trigger the restore functionality when you build.

I have now become a strong supporter of the don’t commit packages workflow, and if you’re going to use it, this is the way to do it!

Tuesday, August 9, 2011

How an OData quirk slowed down NuGet, and how we fixed it

Update: my terminology in this post is not quite correct. Whenever I refer to the server part of OData, I really mean to say ‘WCF Data Services’. OData is the protocol, and WCF Data Services is the specific implementation. So the ‘quirk’ we ran into is a WCF Data Services thing and not an OData thing.

As you may know, NuGet uses an OData feed for its packages. Whenever you install packages, or search for packages from Visual Studio, it goes through this feed, which you can find at http://packages.nuget.org/v1/FeedService.svc/Packages.

If you’re a NuGet user, you may also have noticed that the perf of NuGet searches from Visual Studio had been quite bad in recent months. You’d go to the NuGet package dialog and type a search string, and it would take 10 or more seconds to give you results. Ouch! :(

It turns out that the perf issue was due to a nasty OData quirk that we’ve since worked around, and I thought it might be interesting to share this with others. I’m partly doing this as you might run into this yourself if you use OData, partly to poke a little fun at OData, and also to poke a little fun at ourselves, since we really should have caught that from day one.

A whole stack of query abstractions

When you make an OData query from a .NET client, you go through a whole bunch of abstraction layers before a SQL query is made. Let’s say for example that you’re looking for packages that have the string ‘T4MVC’ in their description. It would roughly go though these stages:

First, in your .NET client, the OData client library would let you write something like:

var packages = context.Packages.Where(p => p.Description.Contain("T4MVC"));

Second, this code gets translated by the OData client LINQ provider into a URL with a query string that looks like this:

?$filter=substringof('t4mvc',Description)

Third, this is processed by the OData server, which turns it back into a LINQ expressing, which in theory will look similar to what you had on the client, which was:

var packages = context.Packages.Where(
    p => p.Description.Contain("T4MVC"));

Of course, the ‘context’ here is a very different beast from what it was in step 1, but from a LINQ expression tree point of view, there shouldn’t be much difference.

And finally, the Entity Framework LINQ provider turns this into a SQL query, with a WHERE clause that looks something like:

WHERE Description LIKE N'%T4MVC%'

And then it executes nice and fast (assuming a proper index), and all is well.

When the abstractions break down

Unfortunately, that clean sequence was not going as planned, resulting is much less efficient queries, which started to get really slow as our package count started to get large (and we’re already at over 7000 as of writing this post!).

So which of these steps went wrong? For us, it turned out to be the third one, where the OData server code was creating a very complex LINQ expression.

To understand why, let’s first briefly discuss OData providers. When you write an OData DataService<T>, you actually have the choice between three types of providers:

  1. An Entity Framework provider which works directly over an EF ObjectContext
  2. A reflection provider which works on an arbitrary context that exposes entity sets that are not tied to a specific database technology
  3. A custom provider, which is something so hard to write that almost no one has ever done it (maybe a slight exaggeration, but not by much!)

Give that we’re using EF, #1 seems like the obvious choice. Unfortunately, the EF provider is very inflexible, as it doesn’t let you use any calculated properties on your entities. In other words, it only works if the only thing you want on your OData feed are fields that come straight from the database. So for most non-trivial apps, it’s not a very usable option, and it wasn’t for us (we have some calculated fields like ReportAbuseUrl).

So we ended up using the reflection provider, and wrapping the EF objects with our own objects which exposed whatever we wanted.

Functionally, this worked great, but what we didn’t realize is that the use of the reflection provider causes OData to switch to a different LINQ expression tree generator which does ‘crazy’ things. Specifically, it makes the bad assumption that when you use the reflection provider, you must be using LINQ to object.

So it protects you by using some ‘null propagation’ logic which makes sure that when you write p.Description.Contain("T4MVC"), it won’t blow up if the Description is ever null. It does this by inserting some conditional checks in the LINQ expression. This is very useful if you are in fact using LINQ to object, but it’s a perf disaster if you are using LINQ to EF!

Now, when translated into SQL, what should have been the simple WHERE clause above was in fact becoming something like this:

WHERE  1 = ( CASE 
               WHEN ( Description LIKE N'%T4MVC%' ) THEN 
               CAST(1 AS BIT) 
               WHEN ( NOT ( Description LIKE N'%T4MVC%' ) ) THEN 
               CAST(0 AS BIT) 
             END ) 

which was running significantly slower. Note that in reality, we’re querying for multiple fields at once, so the final SQL statement ended up being much scarier than this. I’m just using this simple case for illustration.And to make things worse, we learned that there was no way of turning off this behavior. What to do?

 

The solution: use some LINQ ninja skills to restore order

LINQ ninja David Fowler found this an irresistible challenge, and came up with a fix is both crazy and brilliant: he wrote a custom LINQ provider that analyses the expression tree generated by the OData LINQ provider, searches for the unwanted conditional null-check pattern, and eliminates it before the expression gets handed out to the EF LINQ provider.

If you want to see the details of his fix, it’s all on github, split into two projects:

QueryInterceptor (https://github.com/davidfowl/QueryInterceptor) is a helper library that makes it easier to write this type of query modification code.

ODataNullPropagationVisitor (https://github.com/davidfowl/ODataNullPropagationVisitor) builds on QueryInterceptor and specifically targets the removal of the unwanted null check.

Naturally, these are available via NuGet (with the second depending on the first). After importing those packages, all that’s left to do is add one small call to your IQueryable<T>, e.g.

query = query.WithoutNullPropagation();

and your expression trees will be given a gardener’s special pruning :)

Lesson learned: always check your SQL queries

Some might conclude that all those query abstractions are just too dangerous, and we should just be writing raw SQL instead, where this never would have happened. But I think that would be way too drastic, and I certainly wouldn’t stop using abstractions because of this issue.

However, the wisdom we learned is that no matter what query abstractions you’re using (LINQ, OData, or other), you should always run SQL query analyzer on your app to see what SQL statements get run in the end. If you see any queries that doesn't completely make sense based on what your app is doing, get to the bottom of it and address it!

Of course, this is really ‘obvious’ advice, and the fact that we never did that is certainly a bit embarrassing. Part of the problem is that our tiny NuGet team is mostly focused on the NuGet client, and that the server hasn’t been getting enough love. But yes, these are just bad excuses, and in the end, we messed that one up. But now it’s fixed :)

Sunday, July 10, 2011

One big feature social networks really need: Channels

Like many others, I have been playing around with Google+ to see what the new kid on the block has to offer. And it does have some good things going for it, with the concepts of Circles providing a pretty nice approach to privacy.

Unfortunately, it suffers from the same flaw that Facebook and Twitter have always had: it makes the naïve assumption that when you follow someone, you want to hear everything they have to say. In other words, it treats us as one-dimensional beings, which doesn’t match the ‘real world’.

This is something I have always found particularly painful on Twitter, both as a tweet consumer and a tweet producer.

As a consumer, I end up not following a bunch of interesting .NET folks because they’re too ‘noisy’, meaning they tweet about a lot of unrelated things that I don’t care about. I’ve tried to follow Scott Hanselman’s philosophy and let the river of crap wash over me, but it just didn’t work for me. I guess I couldn’t take the smell.

As a producer, I end up not tweeting many things I would want to say, because I know that a lot of my 2500 followers only care about the .NET side, and I don’t want to add crap to their rivers. For instance, I follow tennis closely, but I’m not going to tweet super insightful things like “OMG, Federer lost!!”, because I know most followers don’t care.

So to summarize, I’m missing out as a consumer, and repressed as a producer. Sad! :(

Aren’t Twitter hashtags the way to follow topics instead of users?

Twitter hashtags are an ugly hack over a weak platform, and don’t do much to solve this.

First of all, as a producer, it makes no difference to my followers, since they will see my tweets no matter what hashtags they contain.

As a consumer, hashtags fail pretty badly for a number of reasons. First of all, many people don’t use them correctly. They get misspelled, forgotten, and often conflict with unrelated things. But more importantly, they assume that you want to hear about that topic from everybody, while in many cases I only want to hear what a selected set of users are saying about that topic.

If I could set a search criteria for each user that I follow, I might be getting somewhere, but that’s just not an option today. And even that would work poorly given the inconsistent use of hashtags.

But don’t Google+ Circles solve this issue?

No, not one bit! Circles are about privacy and nothing else. The issue I’m discussing here has nothing to do with privacy; it’s about filtering of public information.

I see people saying that Google+ successfully merges what Facebook and Twitter are good at: connecting with friends and having a public voice. They are wrong! Let’s put that to the test…

Let say I convince all my family to get on Google+ (a tough challenge, but bear with me). I add them to my ‘family’ circle and they do the same thing. We can share family things with great privacy; that’s nice, and is where circles shine.

But now let’s say I’m also using Google+ the way I use twitter today, and write a whole bunch of things about .NET.

What happens when my family members click on their ‘family’ circle? They’re inundated with all that .NET stuff from me that they couldn’t care less about! Their first reaction is that they want to go back to Facebook, where they don’t see that ‘work’ stuff.

Now let’s look at a second scenario: I want to publicly share various things about both .NET and tennis. They key word here is publicly. I don’t want to have to add everyone who can read my tennis and .NET comments two circles, since I want it to be wide open. Circles are just not meant to solve this.

The answer: Channels

One simple way to solve this is to add a concept called ‘channels’. Here is how it would work:

First everyone can (optionally) define a list of channels. In my case, I might create channels called ‘tech’, ‘tennis’, and ‘personal’. For each channel, you can write a one line ‘advertisement’ of what you generally discuss there. e.g. my tech channel might say ‘stuff I work on, mostly related to .NET and NuGet'.

Then whenever you share something, you can choose whether it should go to everyone or just some channel. Note that when I say ‘everyone’ here, I really mean ‘everyone that is allowed to see it’. Again, channels are not a privacy concept; they are orthogonal.

Finally, when you follow someone (i.e. add them to a circle), you get to choose whether you want the whole person, or only some of the channels. e.g. my mom would pick my ‘personal’ channel, while some .NET folks may choose ‘tech’, and others might leave it unfiltered and get it all (which would be the default, as it is today).

As an additional option, you could attach a channel to each circle. e.g. my ‘family’ circle would use to the ‘personal’ channel, so I don’t have to think about it when I share from there. Note that this setting only applies to what I share. For each family member that I follow, I can still select what I want from their channels (which are likely not named the same as mine).

This may seem a bit complicated, but I don’t think it would be in practice, because:

  • Users coming from Facebook who only use it to connect to friends would not define any channels.
  • When you start following someone, you’d typically follow the whole person, as you do today. Then if you start getting too much noise from them, an easy-to-find option would allow you to tune it down. e.g. the context menu on my ‘tennis’ comment would offer “Don’t show any more ‘tennis’ comments from this user”. Conceptually, this is similar to Facebook offering you to ignore Farmville entries from some users, and that’s an easy concept to understand.

So it would not make the platform any less approachable to newbies, but the extra power would be readily available when needed.

Good old blogs have had that forever

Interestingly, if you view ‘things that you share’ as ‘blog posts’, and ‘following someone’ as ‘subscribing to their RSS feed’, you find that the channel feature I describe here is almost identical to the concept of tags/labels in a blog.

e.g. You subscribe to http://blog.davidebbo.com/ to get all my posts, and to http://blog.davidebbo.com/search/label/NuGet to only get my posts about NuGet.

So the basic concept is far from new, but for some reason the big social networks have not caught on to it.

Will this feature ever be available?

Well, that’s good question! My hope is that enough people want it that the big social networks will eventually want to implement something like it.

If I had to choose, I’d prefer Google+ to be the one offering this, since I think it has a model which lends itself to it best.

And if all else fails, I’ll just have to start a new social network. Or not! :)

Saturday, June 25, 2011

Unit test your MVC views using Razor Generator

Click here to find all the posts relating to the Razor Generator

A few days ago, I blogged about how you can use Razor Generator to precompile your MVC Razor views.

In this post, I will demonstrate how you can then unit test your precompiled views. Note that this is still very much experimental, so at this point the primary goal is to get feedback on the concept.
 

Simple walkthrough to unit test views

After installing RazorGenerator, create an MVC 3 Razor app, using the ‘Internet Application’ template and including the unit test project.

In the previous post, we used precompiled views in a different library, so this time let’s keep them in the MVC project to show something different.

First, use NuGet to install the RazorGenerator.Mvc package in your MVC project.
 
Then, as in the previous post, set the custom tool on Views\Home\Index.cshtml to ‘RazorGenerator’, causing Index.cs to be generated under it.
 
But now, let’s do something new and use NuGet again to add the RazorGenerator.Testing package to the unit test project (not to the MVC app!).
 
And that’s all it takes to get set up! Now we can write a unit test for our precompiled Index.cshtml view. e.g. create a Views\HomeViewsTest.cs (in the unit test project):
 
using HtmlAgilityPack;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MvcApplication2.Views.Home;
using RazorGenerator.Testing;

namespace MvcApplication1.Tests.Views {
    [TestClass]
    public class HomeViewsTest {
        [TestMethod]
        public void Index() {
            // Instantiate the view directly. This is made possible by
            // the fact that we precompiled it
            var view = new Index();

            // Set up the data that needs to be accessed by the view
            view.ViewBag.Message = "Testing";

            // Render it in an HtmlAgilityPack HtmlDocument. Note that
            // you can pass a 'model' object here if your view needs one.
            // Generally, what you do here is similar to how a controller
            //action sets up data for its view.
            HtmlDocument doc = view.RenderAsHtml();

            // Use the HtmlAgilityPack object model to verify the view.
            // Here, we simply check that the first <h2> tag contains
            // what we put in view.ViewBag.Message
            HtmlNode node = doc.DocumentNode.Element("h2");
            Assert.AreEqual("Testing", node.InnerHtml.Trim());
        }
    }
}

A few notes about unit testing views

Unit testing views in ASP.NET MVC is something that was very tricky to do before, due to the fact that the views are normally compiled at runtime. But the use of the Razor Generator makes it possible to directly instantiate view classes and unit test them.

Now the big question, is whether unit testing views is desirable. Some people have expressed concerns that it would be a bit fragile due to the changing nature of the HTML output.
 
My take here is that while it would be a bad idea to try to compare the entire HTML output, the test can be made pretty solid by selectively comparing some interesting fragments, as in the sample above.
 
That being said, I have not tried this is a real app, so there is still much to learn about how this will all play out. This is just a first step!
 

What about partial views?

When designing this view testing framework, we took the approach that we wanted to focus on the output of just one view at a time. Hence, if a view calls @Html.Partial(…) to render a sub-view, we don’t let the sub-view render itself, and instead just render a token to mark where the sub-view would be.

This seemed more true to the nature of what a unit test should be, compared to letting the whole composite page render itself, which would be more of a functional test (plus there were some tough challenged to making it work).
 

Where do we go from here?

Well, it’ll be interesting to hear what people think about the general idea. We’re interested in two types of feedback.

First, what do you think about the overall concept of unit testing views using this approach. Second, please report bugs that you run into to http://razorgenerator.codeplex.com/. At this point, I expect it to be a bit buggy and probably blow up on some complex views. Treat it as a proof of concept! :)