Sunday, November 11, 2007

The MVC framework and new C# 3.0 features

You can't get hold of the MVC framework itself yet, but Scott Hanselman has posted the demo code used to demonstrate it at DevConnections and the PNPSummit. Browsing the routing demo code initially left me quite confused until I realized that it was using a couple of new C# 3.0 features: object initializers and anonymous types to initialize the routing engine.

using System;
using System.Web.Mvc;

namespace HelloWorld {
    public class Global : System.Web.HttpApplication {
        protected void Application_Start(object sender, EventArgs e) {

            // Custom "pretty" route
            RouteTable.Routes.Add(new Route {
                Url = "products/[category]",
                Defaults = new {
                    controller = "sample",
                    action = "ShowProducts",
                    category = "beverages"
                },
                RouteHandler = typeof(MvcRouteHandler)
            });

            // Default route
            RouteTable.Routes.Add(new Route {
                Url = "[controller]/[action]/[id]",
                Defaults = new { action = "Index", id = (string)null },
                RouteHandler = typeof(MvcRouteHandler)
            });
        }
    }
}

It initially looks like named arguments, but in fact it's creating a new anonymous type with the named properties. But how does the Route object parse its Defaults property? Does it have to use reflection to find the properties of the Defaults type, or am I missing something?

2 comments:

Bruce Boughton said...

I may be wrong but...

Presumable Defaults (the formal argument) has a type, say Foo. Presumably Foo has a no-arg constructor and properties controller, action, and category.

Not sure why the casing on the property names is wrong but it seems to fit the pattern.

Mike Hadlow said...

Hi Bruce!

Good suggestion, the problem is that the compiler throws it out if you try to implicitly cast an anonymous type to some other type. I tried this code:

[Test]
public void Test()
{
var bar = new Foo() {
Bar = new {
First = "First",
Second = "Second"
}
};
}

public class Foo
{
public Bar Bar { get; set; }
}

public class Bar
{
public string First { get; set; }
public string Second { get; set; }
}

But the compiler complains with:

Cannot implicitly convert type 'AnonymousType#1' to 'Mike.AnonymousPlay.Bar'

If you change Foo's Bar property to object it works:

public class Foo
{
public object Bar { get; set; }
}

But then how do you access Bar's properties except with reflection?