Site Meter
 
 

Monthly Archives: November 2007

In depth: The ASP.NET MVC Pipeline

If what we’ve heard is true, then the new ASP.NET MVC framework will be the most customisable and extensible web development platform Microsoft has ever shipped.

If you want to take advantage of that, or if you’re just trying to make sense of what bit does what, you’ll want to open up the bonnet and check out the engine.

The Pipeline

ASP.NET MVC Pipeline Thumbnail

Disclaimer: this information is based on pre-CTP1 code samples, so it might be outdated or just plain wrong. I will update this post and the diagram when the public CTP is shipped.

Download diagram: PDF, JPEG

0. App initialisation

When the application starts up, like any ASP.NET application, it runs Global.asax’s Application_Start() method.

In this method, you can add Route objects to the static RouteTable.Routes collection (which is of type RouteCollection). These will be inspected later when each request is received. Each Route object defines a URL pattern to be matched and the controller to be used in this case. Optionally, you can specify a controller action and a custom IRouteHandler if you don’t want to use the default (which is MvcRouteHandler).

If you’re implementing a custom IControllerFactory (for example, if you’re using a 3rd-party Inversion of Control container, like Castle Windsor), you can set this as the active controller factory by assigning it to the System.Web.Mvc.ControllerFactory.Instance property.

1. Routing

Overview: Routing is a stand-alone component that matches incoming requests to IHttpHandlers by URL pattern. MvcHandler is, itself, an IHttpHandler, which acts as a kind of proxy to other IHttpHandlers configured in the Routes table.

The combination of System.Web.Mvc.MvcHandler and System.Web.Mvc.UrlRoutingModule references in the web.config give responsibility for handling all incoming requests to MvcHandler.

First, MvcHandler calls Routes.GetRouteData() which matches the incoming request against the list of Route objects added in Application_Start(). The appropriate Route is chosen and a RouteData object prepared. This references the appropriate IRouteHandler and IController to be used.

Next, the IRouteHandler‘s GetHttpHandler() is called, returning an IHttpHandler, whose ProcessRequest() method is finally invoked. The default IHttpHandler as returned by MvcRouteHandler is, again, MvcHandler, which performs steps 2-4 below.

ScottGu offers another view of this routing process.

2. Instantiate and execute controller

Overview: The active IControllerFactory supplies an IController instance

MvcHandler’s ProcessRequest() method calls ControllerFactory.Instance.CreateController(), passing context information including the type of controller obtained in the RouteData object previously.

The active IControllerFactory is responsible for instantiating and returning an appropriate IController. Usually, this will be a subclass of the Controller base class.

The IController’s Execute() method is then called. If this is a subclass of Controller, steps 3 and 4 below are performed.

3. Locate and invoke controller action

Overview: The controller invokes its relevant action method, which after further processing, calls RenderView()

The Controller.Execute() method uses the RouteData and other context information to pick the appropriate action method. This method must have a [ControllerAction] attribute to be eligible for selection. It also maps incoming request parameters (querystring, form etc from the IHttpRequest context object) to the parameter list of the action method.

The controller calls its own InvokeAction() method, passing details of the chosen action method, which, predictably, invokes the action method. This is where your code finally runs.

Within your [ControllerAction] method, you’re expected to call the Controller’s RenderView() method. By this time, you will have populated the controller’s ViewData property. RenderView() performs step 4 below.

4. Instantiate and render view

Overview: The IViewFactory supplies an IView, which pushes response data to the IHttpResponse object.

The view subsystem follows the same factory pattern as routing. That is, the Controller object has a property called ViewFactory which is of type IViewFactory. The IViewFactory interface defines a method called CreateView(), which takes a view name and other context information, using which it instantiates and returns an IView.

The controller can now invoke the IView‘s RenderView() method, supplying the necessary context information, which includes ViewData and the IHttpResponse object to which it can push any text or binary data into the response. This response data may be HTML, an image, or any other binary or text data.

Summary / Conclusion

As a developer working with ASP.NET, you won’t need to worry about the intricacies of IRouteHandler and IViewFactory and the like very often. The typical development process is simply:

  • From Global.asax, add a Route object representing a certain URL pattern you want to catch and map to a controller / action
  • Add a Controller subclass, whose [ControllerActions] should be invoked in response to requests, populating ViewData
  • Add a view template that uses ViewData to render some HTML

The thing to remember is that there are many extensibility points all over the framework, so if you want to build a custom view engine or a custom request routing system, you can hook in at the appropriate points. Hopefully the diagram and explanation above will prove useful if you’re just starting to do that.

kick it on DotNetKicks.com

Castle MonoRail meets jMVC

… and it feels like they’ve known each other forever…

In case you’ve missed my earlier posts, jMVC is a Javascript library that provides a simple but delightfully effective mechanism for client-side interactivity. You can build dynamic UIs where the set of controls changes (lists, hierarchies, grids, drill-downs etc) according to data entered, on the client, using a templating system instead of Javascript event handling or any fiddly AJAX. jMVC uses Model-View-Controller principles to keep things clean and sweet, and so does MonoRail, so it’s a natural fit.

We’ve already integrated jMVC with ASP.NET WebForms, but if you’re lucky enough to be using MonoRail for your web development, you’re going to prefer this version. To clarify: the rest of this post is only relevant for you if you’re using MonoRail. If you’re not, stop reading this and go and learn about MonoRail!

Download / Installation

Download jMVC-Monorail-1.0.zip
(You can also get the source code but we’ll assume you’re using the precompiled DLL)

Put the DLL somewhere in your project directory (e.g. in the bin folder) and add a reference to it.

image

Also, if you don’t yet have a reference to Castle.MonoRail.JSONSupport, add one now.

Put the jMVCplusJson.js javascript file somewhere accessible in your project, for example in the /Content/js/ folder.

image

Add a reference to the jMVCplusJson.js file either in the view(s) that will use it, or more simply in your default layout.

image

You’re now ready to go!

Usage

Just like the post on jMVC.NET, we’ll take as our example a variable-sized editable list of tags. Much more complicated controls are possible, but let’s stick to the basics.

At the top of your controller class, specify that you’ll be using the jMVC helper via the [Helper] attribute. (If it doesn’t seem to work, make sure your project has a reference to jMVC.MonoRail)

image

Also in your controller, put the existing list of tags chosen into the PropertyBag.

image

In the view, add a jMVCHelper.MVCPanel, referencing this item from the PropertyBag:

image

Note, we’ve referenced a jMVC template called taglist.jmvc which doesn’t yet exist. Create a text file matching that filename, and write a template following jMVC syntax, such as:

<% if(model.length == 0) { %>
    The list is empty.
<% } %>

<% for(var i = 0; i < model.length; i++) { %>
    <div>
        <input type="text" value="<%= model[i] %>" onchange="<%* function(i) { model[i] = this.value; } %>" />
        <span onclick="<%* function(i) { model.splice(i, 1); } %>">delete</span>
    </div>
<% } %>

<input type="button" value="Add tag" onclick="<%* function() { model.push(""); } %>" />

Now, if you run your application, you should find that the page displays the list of tags, and the user can add, edit and remove items in the list.

Receiving the post data

So, the user can edit the list, but how do you get it back on the server?

Easy – the form contains a hidden input called “tags” (or whatever else you specified) which contains a JSON representation of the client-side data model. jMVC keeps it up-to-date as the user makes changes.

You can therefore bind the result to a parameter on the action that receives the post data, using the [JSONBinder] attribute included in the Castle.Monorail.JSONSupport namespace.

image

Note – you may need to add a reference to Castle.Monorail.JSONSupport to use this.

Going further

You’re not limited to working with arrays of strings. You can work with arbitrary strongly-typed .NET objects (as long as Castle.Monorail.JSONSupport is able to serialize them to JSON – so most types are OK as long as they don’t reference a huge object graph).

You can learn more about jMVC syntax here, and see more examples on the jMVC.NET pages here.

Troubleshooting

If you get some weird kind of 404-within-a-page error, make sure your web server is configured to serve files with a .jmvc extension. If that’s not possible, rename your .jmvc file to have some other more acceptable extension and change the $jMVCHelper.MVCPanel reference to it.

If you get an error about not being able to find Newtonsoft.Json, Version=1.1.1.0, download the latest build of MonoRail and get the Newtonsoft.Json DLL from there.

Official ASP.NET MVC framework will have first CTP release in ‘next few weeks’

Microsoft’s Matt Gibbs (ASP.NET Program Manager) announced today at the Barcelona TechEd conference that he will ship the first CTP for ASP.NET MVC in “the next few weeks”. It will be contained in the next CTP for ASP.NET “futures”. Since VS2008 (with .NET 3.5) will have a full, final release this month, we might expect them to occur at similar times.

ASP.NET MVC will bring a Ruby-on-Rails-like development experience to ASP.NET and compete with .NET alternatives like Castle Monorail to offer the best agile web development framework. It won’t replace traditional WebForms (yet) but is a complete alternative. We’ve seen the video of the demo at ALT.net conference, and read ScottGu’s blog for a high-level overview, but this will be the first time we can actually get our hands on the bits and try it out.

In Matt’s words, the three major value offerings of ASP.NET MVC are:

  • Clean separation of concerns (supporting red/green test-driven-development)
  • Clean URLs, clean XHTML and full control over all markup
  • Extensibility and pluggability (all system components can be replaced, and it will play nicely with 3rd-party facilities like IoC/DI containers)

He implied that the key advantages of ASP.NET MVC over Monorail (or even RoR) will be

  • Rich tooling (Visual Studio support for intellisense, debugging, project templates etc – though I’d say these are all available in the existing open-source alternatives)
  • Builds on existing ASP.NET infrastructure (so if you’re used to using the caching, session, profile features etc, you still can. Many ASP.NET web controls will continue to work in the new framework, but not all, as there will no longer be a concept of a postback (at last…))

The first CTP will perhaps be a little raw, as for example the ASP.NET AJAX features won’t have any special support for MVC, which means things like UpdatePanels won’t be usable any more. Matt suggested that they will work to port some of these concepts – the ones that you’d still want in MVC anyway – into the new framework.

There will also be limited tooling support, so for example no visual designer for your views.

Timeline

  • Nov 2007: VS2008 has a final RTM release
  • Nov 2007: ASP.NET “futures” has a CTP release, containing MVC for the first time
  • Feb/Mar 2008 (approx): Another ASP.NET “futures” release, with enhanced MVC
  • Later: Final ASP.NET MVC release

As I understand, the first MVC CTP will target Visual Studio 2008 only, but that point wasn’t entirely clear so please wait for confirmation on that.

Update: I checked with one of the Microsoft ASP.NET guys and he believes that ASP.NET MVC will only target .NET 3.5, which means you’ll need to use Visual Studio 2008 and the new framework to use it.

kick it on DotNetKicks.com