code, tech, personal comments edit

One aspect of my job that I love is being able to go in front of other developers, my peers, and give presentations on the technologies that my team and I build. I’m very fortunate to be able to do so, especially given the intense stage fright I used to have.

phil-mvc-talk

But over time, through giving multiple presentations, the stage fright has subsided to mere abject horror levels. Even so, I’m still nowhere near the numbers of much more polished and experienced speakers such as my cohort, Scott Hanselman.

Always looking for the silver lining, I’ve found that my lack of raw talent in this area has one great benefit, I make a lot of mistakes. A crap ton of them. But as Byron Pulsifer says, every mistake is a an “opportunity to learn”, which means I’m still cramming for that final exam.

At this past Mix 11, I made several mistakeslearning opportunities in my first talk that I was able to capitalize on by the time my second talk came around.

I thought it might be helpful for my future self (and perhaps other budding presenters) if I jotted down some of the common mistakes I’ve made and how I attempt to mitigate them.

Have a Backup For Everything!

An alternative title for this point could be worry more! I tend to be a complete optimist when it comes to preparing for a talk. I assume things will just work and it’ll generally work itself out and this attitude drives Mr. Hanselman crazy when we give a talk together. This attitude is also a setup for disaster when it comes to giving a talk.

During my talk, there were several occasions where I fat-fingered the code I was attempting to write on stage in front of a live audience. For most of my demos, I had snippets prepared in advance. But there were a couple of cases where I thought the code was simple enough that I could hack it out live.

Bad mistake!

You never know when nervousness combined with navigating a method that takes a Func-y lambda expression of a generic type can get you so lost in angle brackets you think you’re writing XML. I had to delete the method I was writing and start from scratch because I didn’t create a snippet for it, which was my backup for other code samples. This did not create a smooth experience for people attending the talk.

Another example of having a backup in place is to always have a finished version of your demo you can switch to and explain in case things get out of control with your fat fingers.

For every demo you give, think about how it could go wrong and what your backup plan will be when it does go wrong.

Minimize Dependencies Not Under Your Control

In my ASP.NET MVC 3 talk at Mix, I tried to publish a web application to the web that I had built during the session. This was meant to be the finale for the talk and would allow the attendees to visit the site and give it a spin.

It’s a risky move for sure, made all the more risky in that I was publishing over a wireless network that could be a bit creaky at times.

Prior to the talk, I successfully published multiple times in preparation. But I hadn’t set up a backup site (see previous mistake). Sure enough, when the time came to do it live with a room full of people watching, the publishing failed. The network inside the room was different than the one outside the room.

If I had a backup in place, I could have apologized for the failure and sent the attendees to visit the backup site in order for them to play with the finished demo. Instead, I sat there, mouth agape, promising attendees that it worked just before the talk. I swear!

Your audience will forgive the occasional demo failure that’s not in your control as long as the failure doesn’t distract from the overall flow of the presentation too much and as long as you can continue and still drive home the point you were trying to make.

Mock Your Dependencies

This tip is closely related to and follows up on the last tip. While at Mix, I learned how big keynotes, such as the one at Mix, are produced. These folks are Paranoid with a capital “P”! I listened intently to them about the level of fail safes they put in place for a conference keynote.

For example, they often re-create local instances of all aspects of the Internet and networking they might need on their machine through the use of local web servers, HOST files, local fake instances of web services, etc.

Not only that, but there is typically a backup person shadowing what the presenter is doing on another machine. But this person is following along the demo script carefully. If something goes wrong with the presenter’s demo, they are able to switch a KVM script so that the main presenter is now displaying and controlling the backup machine, while the shadow presenter now has the presenter’s original machine and can hopefully fix it and continue shadowing. Update:Scott Hanselman posted a video of behind-the-scenes footage from Mix11 where he and Jonathan Carter discuss keynote preparations and how the mirroring works.

It’s generally a single get-out-of jail free card for a keynote presenter.

I’m not suggesting you go that far for a standard break-out session. But faking some of your tricky dependencies (and having backups) is a very smart option.

Sometimes, a little smoke and mirrors is a good backup

In our following NuGet talk the next day, Scott and I prepared a demo in which I would create a website to serve up NuGet packages, and he would going visit the site to install a package.

We realized that publishing the site on stage was too risky and was tangential to the point of our talk, so we did something very simple. I created the site online in advance at a known location, http://nuget.haacked.com/. This site would be an exact duplicate of the one I would create on stage.

During the presentation, I built the site on my local machine and casually mentioned that I had made the site available to him at that URL. We switched to his computer, he added that URL to his list of package sources, and installed the package.

The point here is that while we didn’t technically lie, we also didn’t tell the full story because it wasn’t relevant to our demo. A few people asked me afterwards how we did that, and this is how.

I would advise against using smoke and mirrors for your primary demo though! Your audience is very smart and they probably wouldn’t like it the key technology you’re demoing is fake.

Prepare and Practice, Practice, Practice

This goes without saying, but is sometimes easier said than done. I highly recommend at least one end-to-end walkthrough of your talk and practice each demo multiple times.

Personally, I don’t try to memorize or plan out exactly what I will say in between demos (except for the first few minutes of the talk). But I do think it’s important to memorize and nail the demos and have a rough idea of the key points that I plan to say in between demos.

The following screenshot depicts a page of chicken scratch from Scott Hanselman’s notebook where we planned out the general outline of our talk.

IMG_1165

I took these notes, typed them up into an orderly outline, and printed out a simple script that we referred to during the talk to make sure we were on the right pace. Scott also makes a point to mark certain milestones in the outline. For example, we knew that around the 45 minute mark, we had better be at the AddMvcToWebForms demo or we were falling behind.

Writing the script is my way of preparing as I end up doing the demos multiple times each when writing the script. But that’s definitely not enough.

For my first talk, I never had the opportunity to do a full dry-run. I can make a lot of excuses about being busy leading up to the conference, but in truth, there is no excuse for not practicing the talk end to end at least once.

When you do a dry run, you’ll find so many issues you’ll want to streamline or fix for the actual talk. Trust me, it’s a lot better to find them during a practice run than during a live talk.

Don’t change anything before the talk

Around the Around 24:40 mark in our joint NuGet in Depth session, you can see me searching for a menu option in the Solution Explorer. I’m looking for the “Open CMD Prompt Here” menu, but I can’t find it.

It turns out, this is a feature of the Power Commands for Visual Studio 2010 VSIX extension. An extension I had just uninstalled on the suggestion from my speaking partner, Mr. Hanselman. Just prior to our talk, he suggested I disable some Visual Studio extensions to “clean things up”

I had practiced my demos with that extension enabled so it threw me off a bit during the talk (Well played Mr. Hanselman!). The point of this story is you should practice your demo in the same state as you plan to give the demo and don’t change a single thing with your machine before giving the actual talk.

I know it’s tempting to install that last Window Update just before a talk because it keeps annoying you with its prompting and what could go wrong, right? But resist that temptation. Wait till after your talk to make changes to your machine.

Conclusion

This post isn’t meant to be an exhaustive list of presentation tips. These are merely tips I learned recently based on mistakes I’ve made that I hope and plan to never repeat.

For more great tips, check out Scott Hanselman’s Tips for a Successful MSFT Presentation and Venkatarangan’s Tips for doing effective Presentations.

Tags: mix11,mix,presentations,tips

code, open source, asp.net mvc, asp.net, nuget comments edit

Another Spring approaches and once again, another Mix is over. This year at Mix, my team announced the release of the ASP.NET MVC 3 Tools Update at Mix, which I blogged about recently.

Working on this release as well as NuGet has kept me intensely busy since we released ASP.NET MVC 3 RTM only this past January. Hopefully now, my team and I can take a moment to breath as we start making big plans for ASP.NET MVC 4. It’s interesting to me to think that the version number for ASP.NET MVC is quickly catching up to the version of ASP.NET proper. Smile

Once again, Mix has continued to be one of my favorite conferences due to the eclectic mix of folks who attend.

trouble-inc

The previous photo was taken from Joey De Villa’s Blog post.

Me-and-elvis

It’s not just a conference where you’ll run into Scott Guthrie and Hanselman, but you’ll also run into Douglas Crockford, Miguel De Icaza or even Elvis!

I was involved with two talks at Mix which are now available on Channel9 and embedded here.

ASP.NET MVC 3 @:The Time Is Now

In this talk, I cover the new features of ASP.NET MVC 3 and the ASP.NET MVC 3 Tools Update while building an application that allows me to ask the audience survey questions. The application is hosted at http://mix11.haacked.com/.

Errata: I ran into a few problems during this talk, which I will cover in a follow-up blog post about speaking tips I learned due to mistakes I’ve made.

If you attended the talk (or watched it), I learned at the end that the failure to publish was due to a proxy issue in the room’s network that I didn’t have in my hotel room or the main conference area.

I plan to follow up on various topics I covered in the talk with blog posts. For example, I wrote a helper method during the talk that allows you to pass in a Razor snippet as a template for a loop. That’s now covered in this blog post, A Better Razor Foreach Loop.

NuGet in Depth: Empowering Open Source on the .NET Platform

In this talk, Scott and I perform what we call our “HaaHa” show, which is a name derived from a combination of our last names, Phil Haack and Scott Hanselman but pronounced like our aliases PhilHaand ScottHa.

We spent the entire talk attempting to one-up each other with demos of NuGet. Each demo built on the last and showed more and more what you can do with NuGet.

Errata: During the demo, there was one point where I expected a License Agreement to pop up, but it didn’t. I gave a misleading explanation for why that happened. We should have seen the pop-up because we do not install SqlServerCompact by default.

Turns out I ran into an edge case potential bug in NuGet. Usually, when I create a project, I make sure to create a folder for the solution so that the solution is isolated in its own folder. For some reason, I didn’t have that checked and the solution was being created in my temp directory. Thus the packages folder was being shared with every project I’ve created in that folder which made NuGet think that SqlServerCompact was already installed.

If you’ve never accepted that agreement, it will pop up.

The second mistake I made was in describing install.ps1, which indeed runs every time you install it into a project, not once per solution. To get the correct definition, read our documentation page on Creating a Package.

Another minor mistake I made was in describing the Magic 8-Ball, I said it had a dodecahedron inside. I meant to say icosahedron which is a twenty-sided polyhedron.

During the talk, we randomly start talking about a ringtone. That was due to someone’s phone going off in the audience. You can’t hear it in the recording. Smile

Oh, I just pushed MoodSwings to the main feed so you can try it out.

Summary

This was the first time I stayed till the following day of a conference rather than hopping on a cab to the airport immediately after my last talk.

I highly recommend that approach. It was nice to have time to relax after my last talk. A few of us went to ride the rollercoaster at NY NY, walk around the strip, and take in a show JabbaWockeez.

IMG_1183IMG_1188

Tags: aspnetmvc, nuget-gallery, mix11, mix, nuget

razor, code, asp.net mvc comments edit

Yesterday, during my ASP.NET MVC 3 talk at Mix 11, I wrote a useful helper method demonstrating an advanced feature of Razor, Razor Templated Delegates.

There are many situations where I want to quickly iterate through a bunch of items in a view, and I prefer using the foreach statement. But sometimes, I need to also know the current index. So I wrote an extension method to IEnumerable<T> that accepts Razor syntax as an argument and calls that template for each item in the enumeration.

public static class HaackHelpers {
  public static HelperResult Each<TItem>(
      this IEnumerable<TItem> items, 
      Func<IndexedItem<TItem>, 
      HelperResult> template) {
    return new HelperResult(writer => {
      int index = 0;

      foreach (var item in items) {
        var result = template(new IndexedItem<TItem>(index++, item));
        result.WriteTo(writer);
      }
    });
  }
}

This method calls the template for each item in the enumeration, but instead of passing in the item itself, we wrap it in a new class, IndexedItem<T>.

public class IndexedItem<TModel> {
  public IndexedItem(int index, TModel item) {
    Index = index;
    Item = item;
  }

  public int Index { get; private set; }
  public TModel Item { get; private set; }
}

And here’s an example of its usage within a view. Notice that we pass in Razor markup as an argument to the method which gets called for each item. We have access to the direct item and the current index.


@model IEnumerable<Question>

<ol>
@Model.Each(@<li>Item @item.Index of @(Model.Count() - 1): @item.Item.Title</li>)
</ol>

If you want to try it out, I put the code in a package in my personal NuGet feed for my code samples. Just connect NuGet to http://nuget.haacked.com/nuget/ and Install-Package RazorForEach. The package installs this code as source files in App_Code.

UPDATE: I updated the code and package to be more efficient (4/16/2011).

asp.net, asp.net mvc, code comments edit

I’m at Mix11 all week and this past Monday, I attended the Open Source Fest where multiple tables were set up for open source project owners to show off their projects.

One of  my favorite projects is also a NuGet package named Glimpse Web Debugger. It adds a FireBug like experience for grabbing server-side diagnostics from an ASP.NET MVC application while looking at it in your browser. It provides a browser plug-in like experience without the plug-in.

One of the features of their plug-in is a route debugger inspired by my route debugger. Over time, as Glimpse catches on, I’ll probably be able to simply retire mine.

But in the meanwhile, inspired by their route debugger, I’ve updated my route debugger so that it acts like tracing and puts the debug information at the bottom of the page (click to enlarge).

About Us - Windows Internet
Explorer

Note that this new feature requires that you’re running against .NET 4 and that you have the Microsoft.Web.Infrastructure assembly available (which you would in an ASP.NET MVC 3 application).

The RouteDebugger NuGet package includes the older version of RouteDebug.dll for those still running against .NET 3.5.

This takes advantage of a new feature included in the Microsoft.Web.Infrastructure assembly that allows you to register an HttpModule dynamically. That allows me to easily append this route debug information to the end of every request.

By the way, RouteDebugger is now part of the RouteMagic project if you want to see the source code.

To try it out, Install-Package RouteDebugger.

comments edit

Today at Mix, Scott Guthrie announced an update to the ASP.NET MVC 3 we’re calling the ASP.NET MVC 3 Tools Update. You can install it via Web PI or download the installer by going to the download details page. Check out the release notes as well for more details.

Notice the emphasis on calling it a Tools Update? The reason for that is simple. This only updates the tooling for ASP.NET MVC 3 and not the runtime. There are no changes to System.Web.Mvc.dll or any of its other assemblies that ship as part of the ASP.NET MVC 3 Framework. Instead, given that we just released ASP.NET MVC 3 this past January, we focused on improvements to the tools and project templates that we wanted to ship in time for Mix.

To drive this point home, here’s a screenshot of the Programs and Features dialog with ASP.NET MVC 3 RTM installed.

BEFORE

mvc3-installed

And here’s one with the Tools Update installed.

AFTER

mvc3-update-installed

Did you see what changed? If not, I’ll help you. Smile

mvc3-update-installed-highlighted

What’s new in this release?

We’ve added a lot of improvements to the tooling experience in this release. For more details, check out the release notes.

  • New Intranet Project Template that enables Windows Authentication and does not include the AccountController.
  • HTML 5 checkbox to enable HTML 5 versions of project templates.
  • Add Controller Dialog now supports full automatic scaffolding of Create, Read, Update, and Delete controller actions and corresponding views. By default, this scaffolds data access code using EF Code First.
  • Add Controller Dialog supports extensible scaffolds via NuGet packages such as MvcScaffolding. This allows plugging in custom scaffolds into the dialog which would allow you to create scaffolds for other data access technologies such as NHibernate or even JET with ODBCDirect if you’re so inclined!
  • JavaScript libraries within project templates are updatable via NuGet! (We included them as pre-installed NuGet packages.)
  • Includes Modernizr 1.7. This provides compatibility support for HTML 5 and CSS 3 in down-level browsers.
  • Includes EF Code First 4.1 as a pre-installed NuGet package.

We’ve also made several other small changes and fixed several bugs in the MVC tooling for Visual Studio:

  • We did some major cleanup to the AccountController in the Internet project template
  • We now have more “sticky” options that remember their settings even when you restart Visual Studio
  • We have much smarter model type filtering logic in the Add View and Add Controller dialogs

NuGet 1.2 Included

Around 12 days ago, we released NuGet 1.2. If you don’t already have NuGet 1.2 installed, ASP.NET MVC 3 Tools Update will install it for you. In fact, it requires it because of the pre-installed NuGet packages feature I mentioned earlier. When you create a new ASP.NET MVC 3 Tools Update project, the script libraries such as jQuery are installed as NuGet packages so that it’s easy to update them after the fact.

Give it a spin and let us know what you think!

nuget, open source, code comments edit

Hi there, it’s time to shine the bat-signal, or better yet, the NuGet-Signal!

batman-sending-nuget-signalThe NuGet community needs your help! We’re wrestling with some interesting wide ranging design decisions and we need data to test out our assumptions and help us make the best possible choices. I won’t go into too much detail about the specific issue as I don’t want to bias the results of the following survey. I simply want to gather information about common practices by answering a set of questions that mostly have empirical answers.

I think it’s a given that most Visual Studio solutions consist of multiple projects. What’s I’m not so sure about is how often those solutions consist of multiple applications?

For example, is it more common for your solution to have a single core app and all of the other projects support that app?

multi-project-single-app

Or is it more common to have a solution with two different apps such as two WinForm apps or two web apps?

multi-project-multi-app

So please answer the following questions:

This survey requires using a browser that supports iframes.

As an example for that last question, here’s the packages folder for a sample solution I created. It has four packages where there are multiple versions.

packages

Thanks for taking the time to answer these questions. I’ll follow up later with more details on what we’re working on.

And feel free to elaborate in the comments if you have more to say!

nuget, asp.net, code comments edit

As you may know, NuGet supports aggregating packages from multiple package sources. You can simply point NuGet at a folder containing packages or at a NuGet OData service.

A while back I wrote up a guide to hosting your own NuGet feed. Well, we’ve made it way easier to set one up now! And, surprise surprise, it involves NuGet. Smile I’ll provide step by step instructions here. But first, make sure you’re running NuGet 1.2!

Step 1: Create a new Empty Web Application in Visual Studio

Go to the File | New | Project menu option (or just hit CTRL + SHIFT + N) which will bring up the new project dialog and select “ASP.NET Empty Web Application” as in the following screenshot (click to enlarge).

new-project-dialog

This results in a very empty project template.

empty-web-project

Step 2: Install the NuGet.Server Package

Now right click on the References node and select Add Library Package Reference to launch the NuGet dialog (alternatively, you can use the Package Manager Console instead and type Install-Package NuGet.Server).

Click the Online tab and then type NuGet.Server in the top right search box. Click Install on the NuGet.Server package as shown in the following image (click to enlarge).

nuget-dialog

Step 3: Add Packages to the Packages folder

That’s it! The NuGet.Server package just converted your empty website into a site that’s ready to serve up the OData package feed. Just add packages into the Packages folder and they’ll show up.

In the following screenshot, you can see that I’ve added a few packages to the Packages folder.

packages-folder

Step 4: Deploy and run your brand new Package Feed!

I can hit CTRL + F5 to run the site and it’ll provide some instructions on what to do next.

package-site

Clicking on “here” shows the OData over ATOM feed of packages.

package-feed

Now all I need to do is deploy this website as I would any other site and then I can click the Settings button and add this feed to my set of package sources as in the following screenshot (click to enlarge).

Options

Note that the URL you need to put in is http://yourdomain/nuget/ depending on how you deploy the site.

Yes, it’s that easy! Note that this feed is “read-only” in the sense that it doesn’t support publishing to it via the NuGet.exe command line tool. Instead, you need to add packages to the Packages folder and they are automatically syndicated.

nuget, code, open source comments edit

I’m happy to announce the release of NuGet 1.2. It took us a bit longer than we expected to get this release out there, and I’ll explain why later, but for now, go install it!

Upgrade!If you go into Visual Studio and select Tools | Extension Manager, click on the Update tab and you’ll see that this new version of NuGet should be available as an update. It only takes a minute and it really is that easy to upgrade.

For more details about what’s in this release, check out the announcement on nuget.org.

There’s also a new version of NuGet.exe corresponding with this release as well as the Package Explorer. If you have a fairly recent version of NuGet.exe, you can upgrade it by simply running the following command:

NuGet.exe u

076583
fg1019

Thanks to everyone who helped make this happen. I’ll be writing about our plans for 1.3 fairly soon. Smile

code comments edit

A colleague of mine from the Data and Modeling Group mentioned that they have a new senior developer position open working on their new datajs project.

This developer would be responsible for defining how modern web and mobile applications use and interact with data on JavaScript platforms. We deal with and work on defining a number of standards including HTML5’s IndexedDB and OData, as well as provide a new set of end-to-end experiences for accessing, managing, and storing data in JS.

What’s interesting to me is that datajs appears to be an open source project under the MIT license!

From its description on the datajs CodePlex page,

datajs is a new cross-browser JavaScript library that enables data-centric web applications by leveraging modern protocols such as JSON and OData and HTML5-enabled browser features. It’s designed to be small, fast and easy to use. \

For more details about the position, check out the job posting online.

For those of you who are interested but don’t live in Redmond, Washington, this position is in Redmond and requires relocation.

How do I apply?

If you’re interested in the position, please contact Jeff Derstadt jeffders@microsoft.com. I don’t know anything more about the job than what I posted here in this blog post.

I do know that I’ve worked with people on that team as partners on in various capacities and they’re smart folks doing good work. I’m sure my team and your team (should you get the job) would end up working closely together. Smile

asp.net mvc, asp.net, code comments edit

I’m in the beautiful country of Brazil right now (I’ll hopefully blog more about that later) proctoring for the hands-on labs that’s part of the Web Camps agenda.

However, the folks here are keeping me on my toes asking me to give impromptu and deeply advanced demos. It almost feels like a form of performance art as I create brand new demos on the fly. Smile

During this time, several people reported issues binding to a decimal value that prompted me to write a new demo and this blog post.

Let’s look at the scenario. Suppose you have the following class (Jogadoris a soccer player in Portugese):

public class Jogador {
    public int ID { get; set; }
        
    public string Name { get; set; }
        
    public decimal Salary { get; set; }
}

And you have two controller actions, one that renders a form used to create a Jogador and another action method that receives the POST request.

public ActionResult Create() {
  // Code inside here is not important
  return View();
}

public ActionResult Create(Jogador player) {
  // Code inside here is not important
  return View();  
}

When you type in a value such as 1234567.55 into the Salary field and try to post it, it works fine. But typically, you would want to type it like 1,234,567.55 (or here in Brazil, you would type it as 1.234.567,55).

In that case, the DefaultModelBinder chokes on the value. This is unfortunate because jQuery Validate allows that value just fine. I’ll talk to the rest of my team about whether we should fix this in the next version of ASP.NET MVC, but for now it’s good to know there’s a workaround.

In general, we recommend folks don’t write custom model binders because they’re difficult to get right and they’re rarely needed. The issue I’m discussing in this post might be one of those cases where it’s warranted.

Here’s the code for my DecimalModelBinder. I should probably write one for other decimal types too, but I’m lazy.

WARNING: This is sample code! I haven’t tried to optimize it or test all scenarios. I know it works for direct decimal arguments to action methods as well as decimal properties when binding to complex objects.

using System;
using System.Globalization;
using System.Web.Mvc;

public class DecimalModelBinder : IModelBinder {
    public object BindModel(ControllerContext controllerContext, 
        ModelBindingContext bindingContext) {
        ValueProviderResult valueResult = bindingContext.ValueProvider
            .GetValue(bindingContext.ModelName);
        ModelState modelState = new ModelState { Value = valueResult };
        object actualValue = null;
        try {
            actualValue = Convert.ToDecimal(valueResult.AttemptedValue, 
                CultureInfo.CurrentCulture);
        }
        catch (FormatException e) {
            modelState.Errors.Add(e);
        }

        bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
        return actualValue;
    }
}

With this in place, you can easily register this in Application_Start within Global.asax.cs.

protected void Application_Start() {
    AreaRegistration.RegisterAllAreas();
    
    ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());

    // All that other stuff you usually put in here...
}

That registers our model binder to only be applied to decimal types, which is good since we wouldn’t want model binding to try and use this model binder when binding any other type.

With this in place, the Salary field will now accept both 1234567.55and 1,234,567.55.

Hope you find this useful. I’ve had a great time in Buenos Aires, Argentina and São Paulo, Brazil. I’ll probably be swamped when I get back home, but I’ll try to make time to write about my time here.

asp.net, asp.net mvc comments edit

Layouts in Razor serve the same purpose as Master Pages do in Web Forms. They allow you to specify a layout for your site and carve out some placeholder sections for your views to implement.

For example, here’s a simple layout with a main body section and a footer section.


<!DOCTYPE html>
<html>
<head><title>Sample Layout</head>
<body>
    <div>@RenderBody()</div>
    <footer>@RenderSection("Footer")</footer>
</body>
</html>

In order to use this layout, your view might look like.


@{
    Layout = "MyLayout.cshtml";
}
<h1>Main Content!</h1>
@section Footer {
    This is the footer.
}

Notice we use the @section syntax to specify the contents for the defined Footer section.

But what if we have other views that don’t specify content for the Footer section? They’ll throw an exception stating that the “Footer” section wasn’t defined.

To make a section optional, we need to call an overload of RenderSection and specify false for the required parameter.


<!DOCTYPE html>
<html>
<head><title>Sample Layout</head>
<body>
    <div>@RenderBody()</div>
    <footer>@RenderSection("Footer", false)</footer>
</body>
</html>

But wouldn’t it be nicer if we could define some default content in the case that the section isn’t defined in the view?

Well here’s one way. It’s a bit ugly, but it works.


<footer>
  @if (IsSectionDefined("Footer")) {
      RenderSection("Footer");
  }
  else { 
      <span>This is the default yo!</span>   
  }
</footer>

That’s some ugly code. If only there were a way to write a version of RenderSection that could accept some Razor markup as a parameter to the method.

Templated Razor Delegates to the rescue! See, I told you these things would come in handy.

We can write an extension method on WebPageBase that encapsulates this bit of ugly boilerplate code. Here’s the implementation.


public static class Helpers {
  public static HelperResult RenderSection(this WebPageBase webPage, 
      string name, Func<dynamic, HelperResult> defaultContents) {
    if (webPage.IsSectionDefined(name)) {
      return webPage.RenderSection(name);
    }
    return defaultContents(null);
  }
}

What’s more interesting than this code is how we can use it now. My Layout now can do the following to define the Footer section:


<footer>
  @this.RenderSection("Footer", @<span>This is the default!</span>)
</footer>

That’s much cleaner! But we can do even better. Notice how there’s that ugly this keyword? That’s necessary because when you write an extension method on the current class, you have to call it using the this kewyord.

Remember when I wrote about how to change the base type of a Razor view? Here’s a case where that really comes in handy.

What we can do is write our own custom base page type (such as the CustomWebViewPage class I used in that blog post) and add the RenderSection method above as an instance method on that class. I’ll leave this as an exercise for the reader.

The end result will let you do the following:


<footer>
  @RenderSection("Footer", @<span>This is the default!</span>)
</footer>

Pretty slick!

You might be wondering why we didn’t just include this feature in Razor. My guess is that we wanted to but just ran out of time. Hopefully this will make it in the next version of Razor.

asp.net mvc, code, razor comments edit

David Fowler turned me on to a really cool feature of Razor I hadn’t realized made it into 1.0, Templated Razor Delegates. What’s that? I’ll let the code do the speaking.


@{
  Func<dynamic, object> b = @<strong>@item</strong>;
}
<span>This sentence is @b("In Bold").</span>

That could come in handy if you have friends who’ll jump on your case for using the bold tag instead of the strong tag because it’s “not semantic”. Yeah, I’m looking at you Damian :stuck_out_tongue:  I mean, don’t both words signify being forceful? I digress.

Note that the delegate that’s generated is a Func<T, HelperResult>. Also, the @item parameter is a special magic parameter. These delegates are only allowed one such parameter, but the template can call into that parameter as many times as it needs.

The example I showed is pretty trivial. I know what you’re thinking. Why not use a helper? Show me an example where this is really useful. Ok, you got it!

Suppose I wrote this really cool HTML helper method for generating any kind of list.

public static class RazorExtensions {
    public static HelperResult List<T>(this IEnumerable<T> items, 
      Func<T, HelperResult> template) {
        return new HelperResult(writer => {
            foreach (var item in items) {
                template(item).WriteTo(writer);
            }
        });
    }
}

This List method accepts a templated Razor delegate, so we can call it like so.


@{
  var items = new[] { "one", "two", "three" };
}

<ul>
@items.List(@<li>@item</li>)
</ul>

As I mentioned earlier, notice that the argument to this method, <span class="asp">@</span>&lt;li><span class="asp">@</span>item&lt;/li> is automatically converted into a Func&lt;dynamic, HelperResult> which is what our method requires.

Now this List method is very reusable. Let’s use it to generate a table of comic books.


@{
    var comics = new[] { 
        new ComicBook {Title = "Groo", Publisher = "Dark Horse Comics"},
        new ComicBook {Title = "Spiderman", Publisher = "Marvel"}
    };
}

<table>
@comics.List(
  @<tr>
    <td>@item.Title</td>
    <td>@item.Publisher</td>
  </tr>)
</table>

This feature was originally implemented to support the WebGrid helper method, but I’m sure you’ll think of other creative ways to take advantage of it.

If you’re interested in how this feature works under the covers, check out this blog post by Andrew Nurse.

nuget, asp.net, asp.net mvc, code comments edit

Renaming a package ID is a potentially destructive action and one we don’t recommend doing. Why? Well if any other packages depend on your package, you’ve effectively broken them if you change your package ID.

For example, today I wanted to rename a poorly named package, MicrosoftWebMvc, to Mvc2Futures. What I ended up doing is recreating the same package with the new ID and uploading it. That way existing packages that depend on MicrosoftWebMvc aren’t broken.

But now, I have two packages that have the same functionality, but different IDs. Wouldn’t it be nice to eventually remove the old one? I guess I could if I knew that no other package had a dependency on it.

This is where the benefit of having an OData service over the packages in the gallery comes in quite useful. It allows us to construct ad-hoc queries we hadn’t accounted for in our API via an URL. Here’s the URL that shows me a list of all packages that depend on MicrosoftWebMvc.

http://packages.nuget.org/v1/FeedService.svc/Packages?$filter=substringof(‘MicrosoftWebMvc’,%20Dependencies)%20eq%20true&$select=Id,Dependencies

Notice that we’re searching the Dependencies node for the substring “MicrosoftWebMvc” anywhere in it. If my package ID was “web”, this would not be a good query to run, so you might need to tweak it for your use case.

Also, this query only detects direct dependencies. It doesn’t detect transitive dependencies. However, in this case, that’s good enough for my needs.

With this list in hand, I can now approach the MvcContrib folks (who are the only ones that depend on it), and suggest they update their existing packages in place to point to the one with the new ID.

If they do this, am I safe to delete MicrosoftWebMvc?

Not necessarily.

I really need to think twice before I remove the MicrosoftWebMvcpackage because it’s already been downloaded 939 times. For those users who’ve installed it into their applications, they’ll never get updates for that package.

In this particular case, this is not a problem because we never plan to update the Mvc2Futures package. But for a package that’s more widely used and frequently updated, this would be a bigger concern.

In the meanwhile, what I will do is update MicrosoftWebMvc to be an empty package that depends on the correct package. That’s probably a good plan while I wait for packages that depend on it to update.

asp.net, asp.net mvc, razor comments edit

Within a Razor view, you have access to a base set of properties (such as Html, Url, Ajax, etc.) each of which provides methods you can use within the view.

For example, in the following view, we use the Html property to access the TextBox method.

<code.
@Html.TextBox("SomeProperty")
</code>

Html is a property of type HtmlHelper and there are a large number of useful extension methods that hang off this type, such as  TextBox.

But where did the Html property come from? It’s a property of System.Web.Mvc.WebViewPage, the default base type for all razor views. If that last phrase doesn’t make sense to you, let me explain.

Unlike many templating engines or interpreted view engines, Razor views are dynamically compiled at runtime into a class and then executed. The class that they’re compiled into derives from WebViewPage. For long time ASP.NET users, this shouldn’t come as a surprise because this is how ASP.NET pages work as well.

Customizing the Base Class

HTML 5 (or is it simply “HTML” now) is a big topic these days. It’d be nice to write a set of HTML 5 specific helpers extension methods, but you’d probably like to avoid adding even more extension methods to the HtmlHelper class because it’s already getting a little crowded in there.

html-extensions

Well perhaps what we need is a new property we can access from within Razor. Well how do we do that?

What we need to do is change the base type for all Razor views to something we control. Fortunately, that’s pretty easy. When you create a new ASP.NET MVC 3 project, you might have noticed that the Views directory contains a Web.config file.

Look inside that file and you’ll notice the following snippet of XML.

<system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, 
    System.Web.Mvc, Version=3.0.0.0, 
    Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
  <pages pageBaseType="System.Web.Mvc.WebViewPage">
    <namespaces>
      <add namespace="System.Web.Mvc" />
      <add namespace="System.Web.Mvc.Ajax" />
      <add namespace="System.Web.Mvc.Html" />
      <add namespace="System.Web.Routing" />
    </namespaces>
  </pages>
</system.web.webPages.razor>

The thing to notice is the <pages> element which has the pageBaseType attribute. The value of that attribute specifies the base page type for all Razor views in your application. But you can change that value by simply replacing that value with your custom class. While it’s not strictly required, it’s pretty easy to simply write a class that derives from WebViewPage.

Let’s look at a simple example of this.

public abstract class CustomWebViewPage : WebViewPage {
  public Html5Helper Html5 { get; set; }

  public override void InitHelpers() {
    base.InitHelpers();
    Html5 = new Html5Helper<object>(base.ViewContext, this);
  }
}

Note that our custom class derives from WebViewPage, but adds a new Html5 property of type Html5Helper. I’ll show the code for that helper here. In this case, it pretty much follows the pattern that HtmlHelper does. I’ve left out some properties for brevity, but at this point, you can add whatever you want to this class.

public class Html5Helper {
  public Html5Helper(ViewContext viewContext, 
    IViewDataContainer viewDataContainer)
    : this(viewContext, viewDataContainer, RouteTable.Routes) {
  }

  public Html5Helper(ViewContext viewContext,
     IViewDataContainer viewDataContainer, RouteCollection routeCollection) {
    ViewContext = viewContext;
    ViewData = new ViewDataDictionary(viewDataContainer.ViewData);
  }

  public ViewDataDictionary ViewData {
    get;
    private set;
  }

  public ViewContext ViewContext {
    get;
    private set;
  }
}

Let’s write a simple extension method that takes advantage of this new property first, so we can get the benefits of all this work.

public static class Html5Extensions {
    public static IHtmlString EmailInput(this Html5Helper html, string name,       string value) {
        var tagBuilder = new TagBuilder("input");
        tagBuilder.Attributes.Add("type", "email");
        tagBuilder.Attributes.Add("value", value);
        return new HtmlString(tagBuilder.ToString());
    }
}

Now, if we change the pageBaseType to CustomWebViewPage, we can recompile the application and start using the new property within our Razor views.

Html5Helpers

Nice! We can now start using our new helpers. Note that if you try this and don’t see your new property in Intellisense right away, try closing and re-opening Visual Studio.

What about Strongly Typed Views

What if I have a Razor view that specifies a strongly typed model like so:


@model Product
@{
    ViewBag.Title = "Home Page";
}

<p>@Model.Name</p>

The base class we wrote wasn’t a generic class so how’s this going to work? Not to worry. This is the part of Razor that’s pretty cool. We can simply write a generic version of our class and Razor will inject the model type into that class when it compiles the razor code.

In this case, we’ll need a generic version of both our CustomWebViewPage and our Html5Helper classes. I’ll follow a similar pattern implemented by HtmlHelper<T> and WebViewPage<T>.

public abstract class CustomWebViewPage<TModel> : CustomWebViewPage {
  public new Html5Helper<TModel> Html5 { get; set; }

  public override void InitHelpers() {
    base.InitHelpers();
    Html5 = new Html5Helper<TModel>(base.ViewContext, this);
  }
}

public class Html5Helper<TModel> : Html5Helper {
  public Html5Helper(ViewContext viewContext, IViewDataContainer container)
    : this(viewContext, container, RouteTable.Routes) {
  }

  public Html5Helper(ViewContext viewContext, IViewDataContainer container, 
      RouteCollection routeCollection) : base(viewContext, container,
      routeCollection) {
    ViewData = new ViewDataDictionary<TModel>(container.ViewData);
  }

  public new ViewDataDictionary<TModel> ViewData {
    get;
    private set;
  }
}

Now you can write extension methods of Html5Helper<TModel> which will have access to the model type much like HtmlHelper<TModel> does.

As usual, if there’s a change you want to make, there’s probably an extensibility point in ASP.NET MVC that’ll let you make it. The tricky part of course, in some cases, is finding the correct point.

comments edit

It pains me to say it, but ASP.NET MVC 3 introduces a minor regression in routing from ASP.NET MVC 2. The good news is that there’s an easy workaround.

The bug manifests when you have a route with two consecutive optional URL parameters and you attempt to use the route to generate an URL. The incoming request matching behavior is unchanged and continues to work fine.

For example, suppose you have the following route defined:

routes.MapRoute("by-day", 
        "archive/{month}/{day}",
        new { controller = "Home", action = "Index", 
            month = UrlParameter.Optional, day = UrlParameter.Optional }
);

Notice that the month and day parameters are both optional.

routes.MapRoute("by-day", 
        "archive/{month}/{day}",
        new { controller = "Home", action = "Index", 
            month = UrlParameter.Optional, day = UrlParameter.Optional }
);

Now suppose you have the following view code to generate URLs using this route.

@Url.RouteUrl("by-day", new { month = 1, day = 23 })
@Url.RouteUrl("by-day", new { month = 1 })
@Url.RouteUrl("by-day", null)

In ASP.NET MVC 2 the above code (well actually, the equivalent to the above code since Razor didn’t exist in ASP.NET MVC 2) would result in the following URLs as you would expect:

  • /archive/1/23
  • /archive/1
  • /archive

But in ASP.NET MVC 3, you get:

  • /archive/1/23
  • /archive/1

In the last case, the value returned is nullbecause of this bug. The bug occurs when two or more consecutive optional URL parameters don’t have values specified for URL generation.

Let’s look at the workaround first, then we’ll dive deeper into why this bug occurs.

The Workaround

The workaround is simple. To fix this issue, change the existing route to not have any optional parameters by removing the default values for month and day. This route now handles the first URL where month and day was specified.

We then add a new route for the other two cases, but this route only has one optional month parameter.

Here are the two routes after we’re done with these changes.

routes.MapRoute("by-day", 
        "archive/{month}/{day}",
        new { controller = "Home", action = "Index"}
);

routes.MapRoute("by-month", 
        "archive/{month}",
        new { controller = "Home", action = "Index", 
            month = UrlParameter.Optional}
);

And now, we need to change the last two calls to generate URLs to use the by-month route.

@Url.RouteUrl("by-day", new { month = 1, day = 23 })
@Url.RouteUrl("by-month", new { month = 1 })
@Url.RouteUrl("by-month", null)

Just to be clear, this bug affects all the URL generation methods in ASP.NET MVC. So if you were generating action links like so:

@Html.ActionLink("sample", "Index", "Home", new { month = 1, day = 23 }, null)
@Html.ActionLink("sample", "Index", "Home", new { month = 1}, null)
@Html.ActionLink("sample", "Index", "Home")

The last one would be broken without the workaround just provided.

The workaround is not too bad if you happen to follow the practice of centralizing your URL generation. For example, the developers building http://forums.asp.net/ ran into this problem as well during the upgrade to ASP.NET MVC 3. But rather than having calls to ActionLink all over their views, they have calls to methods that are specific to their application domain such as ForumDetailUrl. This allowed them to workaround this issue by updating a single method.

The Root Cause

For the insanely curious, let’s look at the root cause of this bug. Going back to the original route defined at the top of this post, we never tried generating an URL where only the second optional parameter was specified.

@Url.RouteUrl("by-day", new { day = 23 })

This call really should fail because we didn’t specify a value for the first optional parameter, month. If it’s not clear why it should fail, suppose we allowed this to succeed, what URL would it generate? /archive/23?  Well that’s obviously not correct because when a request is made for that URL, 23 will be interpreted to be the month, not the date.

In ASP.NET MVC 2, if you made this call, you ended up with /archive/System.Web.Mvc.UrlParameter/23. UrlParameter.Optional is a class introduced by ASP.NET MVC 2 which ships on its own schedule outside of the core ASP.NET Framework. What that means is we added this new class which provided this new behavior in ASP.NET MVC, but core routing didn’t know about it.

The way we fixed this in ASP.NET MVC 3 was to make the ToString method of UrlParameter.Optional return an empty string. That solved this bug, but uncovered a bug in core routing where a route with optional parameters having default values behaves incorrectly when two of them don’t have values specified during URL generation. Sound familiar?

In hindsight, I think it was a mistake to take this fix because it caused a regression for many applications that had worked around the bug. The bug was found very late in our ship cycle and this is just one of the many challenging decisions we make when building software that sometimes don’t work out the way you hoped or expected. All we can do is learn from it and let the experience factor into the next time we are faced with such a dilemma.

The good news is we have bugs logged against this behavior in core ASP.NET Routing so hopefully this will all get resolved in the next core .NET framework release.

nuget, open source, code comments edit

Today I’m pleased to announce the release of NuGet 1.1 to the VS Extension Gallery and CodePlex. If you have NuGet 1.0 installed, just launch the VS Extension Manager (via Tools | Extension Manager menu) and click on the Updates tab.

If you don’t see any updates, make sure to enable automatic detection of available updates.

Extension
Manager

If you are running VS 2010 SP1 Beta, you might run into the following error message when attempting to upgrade to NuGet 1.1 if you have an older version installed.

Visual Studio Extension Installer
(3)

The workaround is to simply uninstall NuGet and then install it from the VS Extension Gallery.

It turns out that our previous VSIX was signed with an incorrect certificate and our updated VSIX is signed with the correct certificate. VS 2010 SP1 now compares and verifies that the certificates of the old and new VSIX match during an upgrade.

If you don’t have NuGet installed, click the Online tab and type in “NuGet” (sans quotes) to find it.

nuget-in-vs-gallery

The VSIX and updated command line tool (used to create and publish packages) is also available on CodePlex.com.

What’s New in 1.1?

Much of the work in this release was focused on bug fixes. Now that CodePlex.com supports directly linking to filtered views of the issue tracker, I can provide you a link to all the issues fixed in 1.1. Smile

In this post, I’ll highlight some of the new features.

Recent Packages Tab

One of the first changes you might notice is that we have a new tab in the dialog that shows packages that you’ve installed recently. Click the screenshot below for a larger view.

NuGet-Recent-Packages

The recent packages shows the last 20 packages that you’ve directly installed. This often comes in handy when you tend to use the same packages over and over again in multiple projects. Right now, the list simply shows the most recently used, but there has been discussion about perhaps changing the behavior to sort by the packages used most often. Feel free to chime in if you want the behavior changed.

By the way, you can also use the Powershell within the Package Manager Console to get this same information with the –Recent flag to Get-Package.

nuget-ps-recent

Progress Bar During Installation

When you install a package, you’ll now notice a progress bar dialog that shows up with output from installing the package.

Installing

The dialog is meant to give an indication of progress, but also gets out of your way immediately when the installation is complete so you’re not stuck clicking a bunch of Close buttons. But what happens if you actually want to review that output?

Package Manager Output Window

NuGet 1.1 also posts that output to the Output window now. When you go to the Output window, you’ll need to select output from the Package Manager to see that output as in the screenshot.

nuget-output

This allows you to review what changes a package made at your leisure after the fact.

Dependency Resolution Algorithm

NuGet 1.1 includes an update to our dependency resolution algorithm which is described in David Ebbo’s blog post on this topic in the section titled “NuGet 1.1 twist”.

Support for F# Project Types

If you are using F#, this one’s for you.

PowerShell Improvements

Thanks to our newest core contributor, Oisin Grehan a PowerShell MVP who really knows his stuff, NuGet 1.1 has a lot of improvements to the PowerShell Console and scripts. I have to admit, a lot of it is over my head as I’m no PowerShell guru, but we’re now much more compliant with PowerShell conventions. Or so I’ve been told. Oisin has been driving a lot of improvements with our PowerShell support.

We also now execute commands within the Powershell Console asynchronously. This means that a long running command won’t freeze the rest of Visual Studio while it runs.

And many others!

There were a lot of other tweaks, bug fixes, and minor improvements that were not worth mentioning here, but they are all listed in our release notes.

Breaking Changes?

There are some minor changes that hopefully won’t break 99.9% of you. If you recall, we made our PowerShell scripts fit with PowerShell conventions. If you have a package that calls one of these methods, your package might need to be updated.Here’s the list of changes we made:

  • Removed List-Package. Use Get-Package instead.
  • Get-ProjectNames was removed. Use Get-Project instead and examine the Name property.
  • Add-BindingRedirects was renamed to Add-BindingRedirect.

What’s next?

Our hope is to have a monthly point release, though we may adjust some iterations to be longer as needed. To see what we’re planning for the 1.2 release, check out this link of issues for 1.2 (note that by the time you read this, some of these features might already be implemented). We’re constantly refining our planning so nothing is set in stone.

For a small taste of what’s coming in 1.2, check out this video by David Ebbo showing a streamlined workflow for creating packages.

Get Involved!

I bet many of you have some great ideas on what we should and shouldn’t do for NuGet. We’d love to have you come over and share your great ideas in our discussion list. Or if you’re looking for other ways to contribute, check out our guide to contributing to NuGet.

asp.net, nuget, open source comments edit

Over a decade ago, Tim Berners-Lee, creator of the World Wide Web instructed the world know that cool URIs don’t change with what appears to be a poem, but it doesn’t rhyme and it’s not haiku.

What makes a cool URI? \ A cool URI is one which does not change. \ What sorts of URI change? \ URIs don’t change: people change them.

In a related article, URL as UI, usability expert Jakob Nielsen lists the following criteria for a usable site:

  • a domain name that is easy to remember and easy to spell
  • short URLs
  • easy-to-type URLs
  • URLs that visualize the site structure
  • URLs that are “hackable” to allow users to move to higher levels of the information architecture by hacking off the end of the URL
  • persistent URLs that don’t change

The permanence of URLs is a fundamental trait of the web that seems to run counter to one of the benefits of using a feature like ASP.NET Routing. For example, one benefit of routing is you can change a route from {controller}/{action}/{id} to {controller}/{id}/{action} and have every URL in your site corresponding to that route automatically be updated.

This is very nice during development when you’re still fleshing out your URLs and haven’t committed to anything, but once you’ve published your site, changing a route URL violates the sacred trait of URL permanence.

This is exactly where I find myself with Subtext. All of our existing URLs end with the .aspx extension, a practice which Jon Udell convincingly argued is harmful. In the upcoming version of Subtext, we’re moving to extensionless URLs by building upon the great support built into ASP.NET 4 and Routing.

I could simply change our routes to remove the .aspx extension, but that would break nearly every existing URL in every blog running on Subtext. So much for URL permanence, right?

There’s a Better Way

Rather than changing routes, what I really want is a way to simply redirect the existing route to a new route. This is pretty easy, but there are a few caveats to keep in mind that make it non-trivial.

  1. Since you don’t want to generate URLs for the old route, the legacy route should never be selected for URL generation. It’s only for matching incoming requests.
  2. The legacy route should be registered after the new URL to ensure it doesn’t accidentally match and supersede the new URL.

I wrote a library that provides a RedirectRoute and a simple extension method for registering a RedirectRoute that satisfies these conditions. Let’s look at an example of how it would be used.

Let’s suppose we have the following route defined and the site has been published to the web..

routes.MapRoute("old", "foo/{controller}/{action}/{id}");

But later, we decide we want all such URLs to start with /bar instead and we want to re-order the id and action segments of the URL.

Here’s an example of how we can do that using this new library.

var route = routes.MapRoute("new", "bar/{controller}/{id}/{action}");
routes.Redirect(r => r.MapRoute("old", "foo/{controller}/{action}/{id}"))  .To(route);

This snippet registers the new route and passes that route to the RedirectRoute that was returned by a call to the Redirect extension method. The RedirectRoute delegates to the old route to match incoming requests. With this in place, every request matching the old route will be redirected to the new route.

Thus a request for /foo/home/index/123 will be redirected to /bar/home/123/index.

Why The Lambda Expression?

To fully understand what’s going on under the hood, I need to explain why the API takes in a lambda expression rather than simply taking in two routes, old route and new route.

Let’s suppose that the API did just that, simply accepted two routes. Here’s what a naïve attempt to use the method might look like.

var new = routes.MapRoute("new", "bar/{controller}/{id}/{action}");
var old = routes.MapRoute("new", "foo/{controller}/{action}/{id}");
routes.Redirect(old).To(new);

Hopefully it’s immediately apparent why this is not good. The old route is mapped before the redirect route. So the redirect route will never be matched. 

The MapRoute extension method not only creates a route, but it adds it to the route collection. So we could have manually created the route, but that’s a pain if you’re already using the MapRoute method to create the route. Or, we could have done this:

var new = routes.MapRoute("new", "bar/{controller}/{id}/{action}");
var throwAway = new RouteCollection();
var old = throwAway.MapRoute("new", "foo/{controller}/{action}/{id}");
routes.Redirect(old).To(new);

Requiring the user of the API to create a throwaway route collection is ugly when the API itself could do it for you. Hence the lambda expression argument to Redirect. Internally, the method creates a throwaway route collection and calls the expression against that instead of against the main route collection.

Implementation Details

I won’t post the full source here, but the implementation details are pretty simple. Here’s the implementation of GetRouteData which is the method called when matching incoming requests.

public override RouteData GetRouteData(HttpContextBase httpContext) {
    // Use the original route to match
    var routeData = SourceRoute.GetRouteData(httpContext);
    if (routeData == null) {
        return null;
    }
    // But swap its route handler with our own
    routeData.RouteHandler = this;
    return routeData;
}

Notice that I use the source route, which is the old route passed into the redirect route, to match the request, but I swap the route handler with the redirect route. RedirectRoute also implements IRouteHandler. It was a little implementation shortcut I took which happens to work fine in this case.

The implementation of GetVirtualPath is even simpler.

public override VirtualPathData GetVirtualPath(RequestContext requestContext  , RouteValueDictionary values) {
    // Redirect routes never generate an URL.
    return null;
}

We never want to generate a URL to the old route, so this method always returns null.

As mentioned, RedirectRoute implements IRouteHandler, so we should look at its implementation.

public IHttpHandler GetHttpHandler(RequestContext requestContext) {
  var requestRouteValues = requestContext.RouteData.Values;

  var routeValues = AdditionalRouteValues.Merge(requestRouteValues);

  var vpd = TargetRoute.GetVirtualPath(requestContext, routeValues);
  string targetUrl = null;
  if (vpd != null) {
    targetUrl = "~/" + vpd.VirtualPath;
    return new RedirectHttpHandler(targetUrl, Permanent, isReusable: false);
  }
  return new DelegateHttpHandler(    httpContext => httpContext.Response.StatusCode = 404, false);
}

Notice that we make use of the DelegateHttpHandler which is something I wrote about a while ago.

Where to get it?

All the code I showed here is now part of the RouteMagic library I blogged about recently. I’ve updated the package so all you need to do is Install-Package RouteMagicwithin NuGet.

asp.net, code, asp.net mvc, open source comments edit

Over the past couple of years, I’ve written several blog posts on ASP.NET Routing where I provided various extensions to routing. Typically such blog posts included a zip download of the binaries and source code to allow readers to easily try out the code.

But that’s always been a real pain and most people don’t bother. But now, there’s a better way to share such code. Moving forward, I’ll be using NuGet packages as a means of sharing my code samples.

In the case of my routing extensions, I’ve compiled them into a solution I call RouteMagic (source is available on GitHub). This solution includes two packages, RouteMagic.Mvc (extensions specific to ASP.NET MVC Routing) and RouteMagic (more general ASP.NET Routing extensions). The RouteMagic.Mvc package depends on the RouteMagic package.

These packages are available in the NuGet feed!

After installing the RouteMagic.Mvc package, you’ll have the following  features available to you.

The source code for the solution contains the following projects:

  • RouteMagic
  • RouteMagic.Mvc
  • RouteMagic.Demo.Web (ASP.NET MVC Web application used to demo these features)
  • UnitTests

This is just a pet project I put together based on various blog posts I’ve written. I’d love to see some of these ideas eventually make it into the Framework. But until then, you’ll probably see these things make it into Subtext for sure!

asp.net, asp.net mvc comments edit

Ni hao ma!

Hot on the heels of the RTM release of ASP.NET MVC 3, we now have localized versions of ASP.NET MVC in 9 languages! The installation links within the Web Platform Installer was updated. If you want to download the installer yourself, you can go to the English download page and select your language or click on one of the nine languages below:

If you speak one of these nine languages, you can now develop with ASP.NET MVC in your native language. Salud!

nuget comments edit

Last night I got a little treat in the mail from the kind folks at StickerMule. I really appreciate how they support open source projects with such great stickers.

NuGet-Stickers-550x365 Look at all those little NuGets!

Just in time as I have a few events I’ll be going to where I can hand some out such as Web Camps Argentina/Brazil, the MVP Summit, and if I’m selected, Mix 2011.

After that, I need to figure out the best way to give the rest out since I won’t be travelling a whole lot this year. We’ll need to have a Nerd Dinner or something. I’ll give some to Scott Hanselman since he travels a lot too.