January 2010 Blog Posts

Speaking At Mix10

It’s that time of year again when a young man’s thoughts turn to Las Vegas! Yep, it’s another year and another Mix conference (March 15-17, 2010), but this time they’ve changed locations to Mandalay Bay.

mandalay-bay

It looks like my prediction that the Mix conferences would end at Mix 09 did not pan out. ;)

As I did last year, I’ll be giving two talks at Mix 10 this year, one of them with the irrepressible Scott Hanselman.

What’s new in ASP.NET MVC 2

Come see and hear about the latest innovations in ASP.NET MVC 2 and the tooling support in Visual Studio 2008 and 2010. We'll introduce you to a range of productivity (and extensibility) enhancements such as template helpers, model validation, and the new “Areas” feature, which enhances the team development of large Web sites. With template helpers you can get your website up and running for any data entity type without having to create UI. With improved server side validation and brand new client side validation support, your business data model can define the behavior of your application automatically. All this and more!

THE HAAHA SHOW: ASP.NET MVC SECURITY WITH HAACK AND HANSELMAN

Join Phil Haack and Scott Hanselman for this dynamic and unusual security session. The HaaHa brothers will take turns implementing features on an ASP.NET MVC Web Site. Scott will write a feature, and Phil will exploit it and hack into the system. We’ll analyze and discuss the exploits live on stage and then close them one by one. You’ll learn about XSS, CSRF, JSON Hijacking and more. Is *your* site safe from the Haack?

Mix10_LoveTheWeb_blk_240 Lest you think Scott and I have big heads and self inflated egos, I should explain the title of the second talk. Last year Scott and I were supposed to give a talk together at the Norwegian Developer’s Conference, but we were very late in submitting a talk and abstract. As in, we had nothing a week before the conference.

So Rune (the organizer) simply put in the title “The Haacked and Hanselman Show” as a placeholder, and it stuck. This talk will follow in the footsteps of that talk, but in some cases it may be more difficult to give because of security improvements in ASP.NET.

Right now I’m prepping for the talk by attempting to discover a 0 day exploit that I can reveal live as the finale for the talk. Won’t that be fun! ;)

(Yes, I’m kidding you humorless security experts out there)

Anyways, if you’re going to be at Mix, be sure to come by and say hello! Don’t be shy.

Technorati Tags: ,,

Editable Routes Using App_Code

UPDATE: THIS POST IS DEPRECATED!!! I’ve updated the original post for editable routes to work in medium trust and not require a full app domain reload like this approach does. I think that approach may supersede this approach until I learn otherwise. :)

Yesterday I wrote about a technique using dynamic compilation to allow editing routes after you’ve deployed an application without having to manually recompile your application.

I made use of a FileSystemWatcher to monitor a Config directory and dynamically recompiled code when the code file changed. This has one advantage over using the App_Code directory in that the whole App Domain doesn’t need to get recycled when you make changes to your routes.

Today, my co-worker David Ebbo (who’s a master at ASP.NET Build and Compilation system) pointed out one gaping flaw with my approach. It doesn’t work in Medium Trust because the FileSystemWatcher class demands full trust. Doh!

For many business systems, that may not be a concern. But for my blog engine, it’s a huge concern. There are workarounds to the FileSystemWatcher issues, but I decided to take the easy way out and use the App_Code directory approach, since it handles all that crufty logic for watching the file system for me.

In this case, I simply added a new folder named App_Code to my project and copied Routes.cs to that folder.

routes-in-app_code

I then added a new method to RouteRegistrationExtensions. (Note that the actual code has some null reference checking which I omitted here.)

public static void RegisterAppCodeRoutes(this RouteCollection routes) {
  var type = BuildManager.GetType("Routes", false/*throwOnError*/);
  var registrar = Activator.CreateInstance(type) as IRouteRegistrar;
  registrar.RegisterRoutes(RouteTable.Routes);
}

So instead of the method I wrote in my previous post, I call this method. The nice thing here is that this method doesn’t have to worry about attaching a FileSystemWatcher or handling events and reloading routes.

Any time the Routes.cs file is changed, the entire App Domain is restarted and Application_Start is called again.

I want to also point out that a long while ago, I showed a different approach for editable routes using IronRuby that you might be interested in.

You can download the sample project here which includes both methods for doing editable routes.

Technorati Tags: ,,

Editable Routes

UPDATE: 2011/02/13: This code is now included in the RouteMagic NuGet package! To use this code, simply run Install-Package RouteMagic within the NuGet Package Manager Console.

In general, once you deploy your ASP.NET MVC application, you can’t change the routes for your application without recompiling the application and redeploying the assembly where your routes are defined.

routesThis is partly by design as routes are generally considered application code, and should have associated unit tests to verify that the routes are correct. A misconfigured route could seriously tank your application.

Having said that, there are many situations in which the ability to change an application’s routes without having to recompile the application comes in very handy. This is the situation I find myself in as I build a blog engine where the folks who will install may want to tweak the routes without having to recompile the blog’s source code.

In this post, I’ll demonstrate an approach that’ll allow you to define your routes in a content file as code (no XML here!) which you deploy with your application as in the screenshot.

Routes File In Soultion

In my implementation, you need to place the routes in a Config folder in your web root. Note that I used Visual Studio’s Properties dialog to mark the file’s Build Action as “Content” so that it’s not compiled into my application.

Properties

What this means is that the code in the Routes.cs file is not compiled with the application. Instead, we will dynamically compile it. First, let’s look at the contents of that file. It shouldn’t be too surprising.

using System.Web.Mvc;
using System.Web.Routing;
using EditableRoutesWeb;

public class Routes : IRouteRegistrar
{
  public void RegisterRoutes(RouteCollection routes)
  {
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
      "Default",
      "{controller}/{action}/{id}",
      new { controller = "Home", action = "Index", id = "" }
    );
  }
}

One thing you’ll notice is that this class implements an interface named IRouteRegistrar. This is an interface I created and added to my web application (though it could be defined in another assembly).

The code in Global.asax.cs for this application simply calls an extension method I wrote.

protected void Application_Start()
{
  AreaRegistration.RegisterAllAreas();
  RouteTable.Routes.RegisterRoutes("~/Config/Routes.cs");
}

It’s the code in this extension method where the real magic happens.

Before I show the code, there are two concepts at work here that make this work. The first is using the BuildManager to dynamically create an assembly from the Routes.cs file. From that assembly, we can create an instance of the type Routes and cast it to IRouteHandler.

var assembly = BuildManager.GetCompiledAssembly("~/Config/Routes.cs");
var registrar = assembly.CreateInstance("Routes") as IRouteRegistrar;

Once we have an instance of a route registrar, we can call RegisterRoutes on that instance.

The second concept is being able to get notification when the Routes.cs file changes. The clever trick that David told me about is using the ASP.NET Cache object to do that. When you add an item to the cache, you can give it a cache dependency pointing to a file and a method to call when the cache is invalidated.

With those two pieces, we can add a cache dependency pointing to Routes.cs and a callback method which will reload the routes when Routes.cs is changed.

Here’s the full listing for RouteRegistrationExtensions.

public static class RouteRegistrationExtensions
{
  public static void RegisterRoutes(this RouteCollection routes, 
      string virtualPath)
  {
    routes.ReloadRoutes(virtualPath);
    ConfigFileChangeNotifier.Listen(virtualPath, 
      vp => routes.ReloadRoutes(vp));
  }

  static void ReloadRoutes(this RouteCollection routes, string virtualPath)
  {
    var assembly = BuildManager.GetCompiledAssembly(virtualPath);
    var registrar = assembly.CreateInstance("Routes") as IRouteRegistrar;
    using(routes.GetWriteLock())
    {
      routes.Clear();
      registrar.RegisterRoutes(routes);
    }
  }
}

This uses a class called ConfigFileChangeNotifier which is based on some code David wrote for Dynamic Data.

public class ConfigFileChangeNotifier
{
  private ConfigFileChangeNotifier(Action<string> changeCallback)
    : this(HostingEnvironment.VirtualPathProvider, changeCallback)
  { 
  }

  private ConfigFileChangeNotifier(VirtualPathProvider vpp, 
      Action<string> changeCallback) {
    _vpp = vpp;
    _changeCallback = changeCallback;
  }

  VirtualPathProvider _vpp;
  Action<string> _changeCallback;

  // When the file at the given path changes, 
  // we'll call the supplied action.
  public static void Listen(string virtualPath, Action<string> action) {
    var notifier = new ConfigFileChangeNotifier(action);
    notifier.ListenForChanges(virtualPath);
  }

  void ListenForChanges(string virtualPath) {
    // Get a CacheDependency from the BuildProvider, 
    // so that we know anytime something changes
    var virtualPathDependencies = new List<string>();
    virtualPathDependencies.Add(virtualPath);
    CacheDependency cacheDependency = _vpp.GetCacheDependency(
      virtualPath, virtualPathDependencies, DateTime.UtcNow);
      HttpRuntime.Cache.Insert(virtualPath /*key*/,
        virtualPath /*value*/,
        cacheDependency,
        Cache.NoAbsoluteExpiration,
        Cache.NoSlidingExpiration,
        CacheItemPriority.NotRemovable,
        new CacheItemRemovedCallback(OnConfigFileChanged));
  }

  void OnConfigFileChanged(string key, object value, 
    CacheItemRemovedReason reason) {
    // We only care about dependency changes
    if (reason != CacheItemRemovedReason.DependencyChanged)
      return;

    _changeCallback(key);

    // Need to listen for the next change
    ListenForChanges(key);
  }
}

With this in place, you can now change routes within the Routes.cs file in the Config directory after you’ve deployed the application. Note that technically, a recompilation is happening, but it’s happening dynamically at runtime when the file changes and there’s no need to restart your entire App Domain, which is one benefit of this approach over using the code in App_Code.

If you want to try this code out, you can download a sample project here. The sample app is compiled against ASP.NET MVC 2 RC, but the same principles and code can be used with an ASP.NET MVC 1.0 application. In fact, it can also be used in an ASP.NET 4 Web Forms application since we now support page routing.

Note, if you want to see the old version of this code, I’ve archived it here.

If You’re Graduating Soon, Consider Working For The ASP.NET Team

This is the second job posting in two days for positions on the ASP.NET team, how exciting! This one is a developer position for upcoming graduates.

Before I continue, I need to fulfill a promise to a co-worker to include a barely relevant stock photograph in this blog post.

Good, with that out of the way, allow me to continue.

If you are in college or grad school, graduating in 2010, and are looking for a great job writing code for ASP.NET, we have a position available!  Send me your resume and I’ll forward it along to the proper people.

My email address is philha at (my company).com where (my company) is Microsoft. If you can’t figure out based on that where to email your resume, you probably shouldn’t bother applying ;)

Once again, this is for college or graduate school students graduating in 2010. If you’re not an upcoming graduate, consider we also have a QA position available.

I look forward to seeing you roam the halls of building 42.

Technorati Tags: ,,,

Join My Team And Help Us Produce Higher Quality Products

The ASP.NET Team is still looking for that QA person out there who shares our passion for technology and improving the means by which software is made.

Keep in mind that the QA position on our team is not someone who mindlessly follows a script hoping by sheer random luck to find bugs. Oh no no no my friends.

This is considered a software development position in which you will be responsible for improving the processes and tools we have in place for ensuring quality software. You’d be involved in improving the quality of all phases of product development as a valued member of a feature crew. Think broadly about the idea of software quality. Your role is to question whether we’re building the right product as much as it is to test the product once it is built.

Matt Osborn, a member of the ASP.NET MVC feature crew has a description of the position.

That’s right you read the title right the ASP.NET QA team is once again hosting ninja try outs. We are looking for someone who is able to help evolve the team processes, improve our tooling, and join us in the trenches as we test one of the best technologies out there. Overall the team is responsible for ASP.NET WebForms, ASP.NET MVC, Microsoft AJAX, and a whole slew of other technologies. Our technologies can be found in numerous large scale web sites such as MySpace.com, Dell.com andDeals.Woot.com.

Once again we would like to find someone that shares our passion for our technology and our trade and someone that has spent sometime in the trenches. So if this sounds like something you’re interested in polish your nun chucks, practice your disappearing skills, and slice your way through our job posting. In the meantime while your sword is out for sharpening send Mark Berryman (one of our managers) an email.

PS: If you listen to the Coding QA podcast you can get a good feel for what it is like being the frontline testing ninjas for ASP.NET. We had a great turn out last time and please feel free submit your resume again it can’t hurt.

Keep in mind we’re not looking for “test” ninjas as in “sample” ninjas. We’re looking for the real deal, brimming with throwing stars of bug finding. Ok, the analogy breaks down a bit there. But you get the picture.

And before I forget, here’s the direct link to the job description on the Microsoft careers site.

Tags: , ,

Do Not Adjust Your Browser

This blog is experiencing technical difficulties. Do not adjust your browser.

Hi there. If you’ve tried to visit this blog recently you might have noticed it’s been down a lot in the last two days. My apologies for that, but hopefully you found what you needed via various online web caches.

I’ve been dogfooding the latest version of Subtext and as CodingHorror points out, dogfood tastes bad.

I’ve done a lot of testing on my local box, but there are a class of bugs that I’m only going to find on a high traffic real site, and boy have I found them!

Some of them might be peculiar to my specific data or environment, but others were due to assumptions I made that were wrong. For example, if you use ThreadPool.QueueUserWorkItem to launch a task, and that task throws an unhandled exception, that can bring your entire App Domain down. Keep that in mind if you think to use that method for a fire-and-forget style task.

In any case, the point of this post is to say that we’re not going to release the next version of Subtext until it’s rock solid. My blog going down occasionally is the cost I’m incurring in order to make sure the next version of Subtext is a beast that won’t quit.

Technorati Tags: ,

Ambiguous Controller Names With Areas

Note: This describes the behavior of ASP.NET MVC 2 as of the release candidate. It’s possible things might change for the RTM.

When using areas in ASP.NET MVC 2, a common problem you might encounter is this exception message.

The controller name 'Home' is ambiguous between the following types:
AreasDemoWeb.Controllers.HomeController
AreasDemoWeb.Areas.Blogs.Controllers.HomeController

This message is telling you that the controller factory found two types that match the route data for the current request. Typically this happens when you have a controller of the same name in an area and in the main project.

For example, in the screenshot below, notice that we have a HomeController in the main Controllers folder as well as in the Blogs area.

area-with-ambiguous-controller

If you make a request for the area such as /Blogs/Home, you’ll find that everything works hunky-dory. However, if you make a request for the root HomeController, such as /Home, you’ll get the ambiguous controller exception.

Why is that?

When you register routes for an area, they get a namespace associated with each route. That ensures that only controllers within the namespace associated with that area can fulfill the request. Thus the request that matches an area will have that namespace and the namespace is used to disambiguate controllers.

But by default, the routes in the main application don’t have a namespace associated with them. That means the controller factory will scan all types looking for a match, and in this case finding two types which match the controller name “Home”.

The Fix

There are two very simple workarounds. The simplest falls in the “If it hurts, stop doing that” camp which is to simply avoid naming two controllers the same name.

For many situations, this is not a satisfactory answer. The other workaround, as you might guess from my explanation of why this happens, is to give the route in the main application a specific namespace. Here’s an example of the default route in Global.asax.cs which has the fix.

public static void RegisterRoutes(RouteCollection routes)
{
  routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

  routes.MapRoute(
    "Default",                                              // Route name
    "{controller}/{action}/{id}",                           // URL
    new { controller = "Home", action = "Index", id = "" }, // Defaults
    new[]{"AreasDemoWeb.Controllers"}                       // Namespaces
  );
}

In the code above, I added a fourth parameter which is an array of namespaces. The controllers for my project live in a namespace called AreasDemoWeb.Controllers.

Follow Up

In a follow-up post, I’ll walk through more details about areas and how namespaces play into routing and controller lookup. For now, I hope this gets you unstuck if you’ve run into this problem before.

Technorati Tags: ,,

Death to confirmation dialogs with jquery.undoable

Confirmation dialogs were designed by masochists intent on making users of the web miserable. At least that’s how I feel when I run into too many of them. And yes, if you take a look at Subtext, you can see I’m a perpetrator.

Well no longer!

I was managing my Netflix queue recently when I accidentally added a movie I did not intend to add (click on the image for a larger view).

netflix-queue Naturally, I clicked on the blue “x” to remove it from the queue and saw this.

netflix-queue-deleted Notice that there’s no confirmation dialog that I’m most likely to ignore questioning my intent requiring me to take yet one more action to remove the movie. No, the movie is removed immediately from my queue just as I requested. I love it when software does what I tell it to do and doesn’t second guess me!

But what’s great about this interface is that it respects that I’m human and am likely to make mistakes, so it offers me an out. The row becomes grayed out, shows me a status message, and provides a link to undo the delete. So if I did make a mistake, I can just click undo and everything is right with the world. Very nicely done!

I started to get curious about how they did it and did not find any existing jQuery plugins for building this sort of undoable interface, so I decided this would be a fun second jQuery plugin for me to write, my first being the live preview plugin.

The Plugin

Much like my jQuery hide/close link, the default usage of the plugin relies heavily on conventions. As you might expect, all the conventions are easily overriden. Here’s the sample HTML for a table of comments you might have in the admin section of a blog.

<table>
    <thead>
        <tr>
            <th>title</th>
            <th>author</th>
            <th>date</th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>This is an interesting plugin</td>
            <td>Bugs Bunny</td>
            <td>12/31/2009</td>
            <td><a href="#1" class="delete">delete</a></td>
        </tr>
        <tr>
            <td>No, it's a bit derivative. But nice try.</td>
            <td>Derrida</td>
            <td>1/1/2010</td>
            <td><a href="#2" class="delete">delete</a></td>
        </tr>
        <tr>
            <td>Writing sample data is no fun at all.</td>
            <td>Peter Griffin</td>
            <td>1/2/2010</td>
            <td><a href="#3" class="delete">delete</a></td>
        </tr>
    </tbody>
</table>

And the following is the code to enable the behavior.

$(function() {
    $('a.delete').undoable({url: 'http://example.com/delete/'});
});

By convention, when one of the delete links is clicked, the value in href attribute is posted as form encoded data with the key “id” to the specified URL, in this case http://example.com/delete/.

If you have more form data to post, it’s quite easy to override how the form data is put together and send whatever you want. The following examples pulls the id from a hidden input and sends it with the form key “commentId”.

$(function() {
  $('a.delete').undoable({
    url: 'http://example.com/delete/',
    getPostData: function(clickSource, target) {
      return {
        commentId: target.find("input[type='hidden'][name='id']").value(),
        commentType: 'contact'
      };
    }
  });
});

When the data is posted to the server, the server must respond with a JSON object having two properties, subject and predicate. For example, in ASP.NET MVC you might post to an action method which looks like:

public ActionResult Delete(int id) {
  // Delete it
  return Json(new {subject = "The comment", predicate = "was deleted"});
}

The only reason I broke up the response message into two parts is to enable nice formatting like Netflix’s approach.

This of course is is easily overridden. For example, it may be simpler to simply return  I can override the formatStatus method to expect other properties in the response from the server. For example, suppose you simply want the server to respond with one message property, you might do this.

$(function() {
  $('a.delete').undoable({
    url: 'http://example.com/delete/',
    formatMessage: function(response) {
      return response.message;
    }
  });
});

I wrote the plugin with the TABLE scenario in mind as I planned to use it in the comment admin section of Subtext, but it works equally well with other elements such as DIV elements. For example, the user facing comments of a blog are most likely in a list of DIV tags. All you need to do to make this work is make sure the DIV has a class of “target” or override the getTarget method.

If you want to see more examples of how to use the plugin in various scenarios, check out the jquery.undoable demos page.

I need your help!

I really hope some of you out there find this plugin useful. Writing these plugins has been a great learning experience for me. I found the following two resources extremely valuable.

  • jQuery Plugin Authoring Guide This is the beginners guide on the jQuery documentation page. I found it to be very helpful in learning the basics of plugin development.
  • A Plugin Development Pattern by Mike Alsup. Mike outlines a pattern for writing jQuery plugins that has worked well for him based on his extensive experience. I tried to follow this pattern as much as I could.

However, I still feel there’s room to improve. I’m not sure that I fully grasped all the tips and wrote a truly idiomatic usable extensible clean jQuery plugin. So if you have experience writing jQuery plugins, please do enumerate all the ways my plugin sucks.

If you simply use this plugin, please tell me what does and doesn’t work for you and how it could be better. I’m really having fun writing these plugins and would find your constructive feedback very helpful.

The Source

As with my last plugin, the source is hosted on GitHub. Git is another tool I’m learning. I can’t really make a judgment until I use it on a project where I’m collaborating with others *hint* *hint*. :) Please do fork it and provide patches and educate me on writing better plugins. :)