Archive for October 2009
Fast. Seriously, embarrassingly fast. Nice job! 🙂
Just read at Mary-Jo Foley’s blog that it looks like a lot of the VS 2010 Team Editions are being reworked. But the also mentions a change in SKU’s and that has me wondering if a Visual Studio 2010 Standard edition will be released. I’ve purchased VS 205 and 2008 editions and thought it was a great way to get all the languages without a lot of the Pro edition bells and whistles. And I thought it was worth paying for between $199 – $299.
I would love to hear from Microsoft what is happening to this edition and the future of the express editions.
Last weekend I enthusiastically went on and on about using Strong-Typed routes in MVC 2 Preview 2 based on Goran Gagic’s elegant sample. And so I have built on his code and I have something to share.
I am going to dive more into usage than working internals, so let’s get underway.
I have made some configuration changes to the sample project to better illustrate the feature set and make usage very convenient when constructing views. First, I have added a few namespaces to the web.config as you can see in the image below:
The namespace ‘MVC2_TypedRoutes.TypedRoutes’ (the ‘TypedRoutes’ folder) contains the extensions and support classes for strong-typed route value creation. Secondly, I have added an additional routes in the global.asax as show below:
Both of these routes utilize the TypedRoutesController exclusively, but differ in their signature using the ‘_RouteName’ value. I have also set up a simple controller that will be used to demonstrate the features. Let’s look at the controller:
There are several attributes applied here that are leveraged by the strong-typed route extensions. Let’s review them:
This attribute has a single property named ‘PassThru’ that allows for a entering a comma separated list of route value names to be passed thru when creating routes. This attribute can be applied to a class or method.
In the sample it is applied to the class, so all strong-typed routes created for the TypedRoutesController will have the ‘_RouteName’ route values passed along when generating a route call.
This attribute allows for specifying a format for the values in the route (especially handy for dates), default values and if the parameter is ignored in creating the route. It can be applied to parameters or properties.
In the sample as applied to the ‘Date’ parameter in the ‘Sample1’ action method it specifies a default DatetTime of Jan 1, 2000. If the date value submitted when creating the strong-typed route in an Html.ActionLink<Controller> extension matches the default, it will not be passed to the resulting route. Additionally, the ‘Format’ value is specified and a route friendly format for the date parameter will be used.
Additionally, the ‘Sample2’ action method has the MVC BindAttribute applied and this will be used by the strong-typed route extensions as well.
The sample get’s right to the point, creating three strong-typed routes inside the HomeController ‘Index’ view to the TypedRoutesController. Let’s take a look at the ActionLink<Controller> calls and the resulting routes.
Sample ActionLink Route 1
Here’s the run down on using the strong-typed ActionLink:
- It’s a generic method – so you have to specify the controller
- The first parameter is simple – the title for the action link
- The second parameter is an expression based call to a method on the TypedRoutesController, in this case ‘Sample1’. (Notice the date supplied is the same as the default specified by the RouteValueAttribute.)
- The third parameter is something I have not mentioned yet. This is a expression call that leverages a fluent-interface object that allows you to easily set route values, route value formats, and html attributes. Let’s take a look at the signature of the fluent-interface object:
As you can see you can apply single or multiple attributes, formats or values. And for attributes I used the JQuery ‘Attr’ for html attributes. (Important note: any formats or route values specified here will override those specified by by the RouteValueAttribute applied to the action method or the method expression provided by calling the Html.ActionLink<C> extension or Url.Action<C> extensions. Phew!)
In this case we are submitting a route value for ‘_RouteName’ of ‘TypedRoutes1’.
Here is the resulting route:
Here is a brief run down:
- The Date RouteValueAttribute default is matched so the value from the ActionLink extension is not passed along in the route.
- The route ‘TypedRoutes1’ is called specified by supplying the appropriate ‘_RouteName’ value.
Sample ActionLink Route 2
Let’s look at the differences:
- We are calling the same action method as in sample 1 above, but this time we are specifying the current time.
- This time we are submitting a route value for ‘_RouteName’ of ‘TypedRoutes2’.
Here is the resulting route:
Notice it correctly chose the ‘TypedRoutes2’ route and submitted a date value formatted as specified by the RouteValueAttribute applied to the method Date parameter.
Sample ActionLink Route 3
Here is the brief run down:
- This sample calls a different action, one that takes a complex object.
- Like sample 2above we are submitting a route value for ‘_RouteName’ of ‘TypedRoutes2’.
- Also, if we look at the controller it has a BindAttribute applied with a prefix. This will be used in formatting values in the route.
- Also we are specifying a custom format for ‘TestObject.Date’.
Here is the resulting route:
That’s It for Now
But before I go a few additional notes:
- This was compiled for MVC 2 Preview 2 but can easily be made to work under MVC 1 by removing the ‘ToHtmlString’ method calls which are new in MVC 2 Preview 2.
- The RouteValueAtrribute can be applied to properties in complex objects being used as action method parameters, but I have not made extensive testing of this.
- There are additional views in the sample project that shows off the subtle power of using the ‘PassThru’ property of the RouteActionAttribute.
- There are also Action methods of the Url helper for use in view or controllers.
I’m setting here and looking back at when I last made an entry – September 20th. Been a while. Work as been very busy and I’ve been engrossed in exploring MCV 2 on my own time. So let’s get to it.
Strong-Typed Route Links
I have been investigating this heavily the past week or two. Based on past experience I have found the notion of un-typed, “magic string” routes to be a bit of insanity. So, with it appearing that strong-typed route links are no longer on the MVC 2 roadmap finding a solution was paramount. I’ve seen two nice solutions thus far.
The first thing I found was David Ebbo’s T4MCV t4 template. It’s a very nice piece of work. You’ll find it on codeplex along with the the MCV 1 source code. Here’s the link: http://aspnet.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=24471
Setting up T4MVC was quite easy. Just drop it into your project root and go. It will create strong-typed routes, links to scripts and much more. It’s a very nice piece of T4 template work. However, I personally had a few concerns. The biggest is the method you call to create the route is not the same method in your controller, it’s an overload that returns the values in a special ActionResult object. Now – you might be thinking – what’s the problem? Let’s say I want to use my own attributes to control how parameters are formatted in making a route. (Specifically, I wanted to format a DateTime object because the default ‘ToString’ representation is not route friendly at all. ) Since it’s an overload the attributes are not there, T4MVC does not copy them, and for met to put them there and use them takes a lot of T4 hacking that I really don’t want to get to (no Intellisense). So while I really respect the work – it wasn’t what something I could easily tool to my liking. So with great regret, I pulled out T4 MVC based and went solution hunting again. What was I after? I was looking for an expression (as in lambda expression) based solution. And then I stumbled on on Goran Gagic’s sample. Here’s the link:
Curiously, it’s the only blog entry he has. But it’s a gold mine. He has a very nicely written sample solution ( even saith The Haack ) that serves as a foundation for building a strong-typed route link system, and also serves as an well documented insight into using lambda expression. So I’ve taken the sample and worked in the ideas I wanted to implement and will be posting a full solution in the next few days. But here is a bit of my thinking on why I wanted this kind of solution in the first place.
The main conclusion I had when trying to work with T4MVC is that while a controller action method can serve as the basis for making a strong-typed route link there needs to be tools for formatting the route derived from the method. And after considering several avenues I decided on attributes directly applied to the controller action method. Why? They’re already being used to nice effect already. For example the ‘ActionName’ attribute allows you to have a different route name (say if want to use a logical method name but also want the same method to be the controller’s ‘Index’ action). In MVC 2 the ‘DefaultValue’ attribute allows you set a default for parameters not passed along in the route. (This is a nice workaround for .net 3.5 and won’t be necessary for 4.0 as C# 4.0 supports optional parameters with default values). And the ‘Bind’ attribute allows you to choose a prefix for a parameter and even set includes/excludes on complex objects. So creating a ‘RouteValue’ attribute is a logical extension. Here’s an example (this method exists in a controller class named ‘ArticleVisualController’ as you will see later ):
In this case the RouteValue attribute is supplying two kinds of detail. First for the ‘id’ parameter it’s supplying the format of the DateTime to be used in the route. Secondly on the ‘id’ and ‘index’ parameters it’s providing a default value, and if the parameter value from the called method expression matches the default it will not be added to the RouteValues dictionary. Here are examples of creating an action link for the method above:
Here are the corresponding routes created:
You can see in both resulting routes the DateTime is formatted as requested (ModelBinding ‘magic’ will ensure it’s a real DateTime object when the controller action method is called in the request) and in the first route the ‘index’ parameter is not added as the value matches the default.
Here is a list of things I will looking to support:
- Route parameter formatting
- Route parameter default values
- Using the ‘Bind’ attribute ‘prefix’, ‘include’ and ‘exclude’ properties
- Using the ‘ActionName’ attribute
- Support for complex parameter types
- And a few others …
I have about 75% of this work done and need to polish for a sample release hopefully next weekend.
Thank you Goran Gagic! You have shown the way!
Lambda Expression Compile Caching Namespace
Honest! The API has it’s own name space and supports several expression types. It looks like this was made to speed the DataAnnotations work, but it’s all internal. Having an open API would help. Wondering if that’s in the plan (or could be) for the beta. Lots of MVC blog posts seem to be leaning towards expression usage and having Lambda Expression compile caching out of the box would be helpful.
And on that matter, is Lambda Expression compile caching a part of .Net 4.0? If not – curious to know why?
Client Side Validation
It works! All you have to do is link to the jQuery and asp.net Ajax scripts and it works. It is not implemented when using ‘Ajax.BeginForm’ – and this is probably a good idea since you never know what’s coming back and avoids wire up problems.
Areas and Related Tips
Nicely done. I am hoping there will be an ‘areas’ folder out of the box added to new projects to the beta. Why? See the first tip below.
- Area view compilation problems. If you run into this just copy the ‘web.config’ from the normal ‘View’ folder and place it under the ‘area’ folder. This will give your views the appropriate compilation settings and prevents them from being viewed by direct url call.
- Controller namespace in ‘Areas’. If you move a controller from the normal “Controllers’ to a custom area ‘Controllers’ folder be sure to update the namespace. If not it won’t be available and you’ll be stuck with a 404 error.
Lambda Expression Programming Insights?
Does anybody know of any good resources for this? What I don’t mean by this is how to write expressions for linq – but for documentation, tutorials and/or books on how to do custom programming with them as the strong-typed route link Goran’s sample does. I would love to grok it.