Making Routes Grow Up a Little
March 19th, 2008
When I saw Scott Hanselman’s first screencast tutorial on ASP.NET MVC Preview 2 I immediately asked “Where’s the named routes?” For those who don’t know, named routes is an extremely useful feature in Ruby on Rails that allows you to create a route and give it a name (if you don’t know what I’m talking about with the whole “route” thing, check out this screencast which goes over it).
The purpose of named routes is to define your URL in one place (the routes file) and give it a unique identifier (a name). Then, throughout the rest of your application you can get that URL by referencing the name, instead of typing the entire URL. Because of this, when your site structure changes (and let’s face it, it will), you only need to change the URL in one place, instead of all over your application. This is in keeping with the DRY principle (Don’t Repeat Yourself) that permeates Rails.
In response to my comment on his blog, Scott says that named routes are possible, but no amount of Googling has shown me how. Well, as any good developer does, I went ahead and figured it out for myself. So here it is, making your routes grow up by adding names.
The process is actually very simple. The name is an optional first parameter to the RoutesCollection.Add method called in your Application_Start. So we can define the following:
routes.Add("send_message", new Route("message/new/{id}", new MvcRouteHandler()));
This defines a route to the “message” controller, calls the “new” action, and passes a parameter called “id”. To access this route in your view, all you have to do is call Html.RouteLink like so:
<%= Html.RouteLink("[send a message]", "send_message") %>
and voila! You now have name routing in an ASP.NET application! It’s just getting cooler every day, isn’t it?
- Posted 3 months ago
- comments[0]
- Permalink
- Digg This!
Making HtmlHelper.TextBox Act Like it Should!
March 18th, 2008
I was working on my ASP.NET MVC demo and tried something new. I’ve been dying to be able to create form fields just like I can in Rails and MonoRail. So in Rails I can say:
<%= text_field :title %>
and in Monorail I can say (syntax may be a little rusty, forgive me, it’s been awhile):
<%= FormHelper.TextField("employee.FirstName") %>
and both will generate the similar code (given an employee named Joe):
<input type="text" name="employee.FirstName" id="employee_FirstName" value="Joe">
Notice that the framework automatically fills the value for employee.FirstName in the textbox. This is very nice for reusability because you no longer have to conditionally pass in the value of your textbox based on whether or not FirstName is null. Using either of these two frameworks I can now reuse the EXACT SAME form control for both Add & Edit. Beautiful.
Now imagine my dismay when I typed a similar command into the ASP.NET MVC Framework:
<%= Html.TextBox("employee.FirstName") %>
and got as output (paraphrasing):
<input type="text" name="employee.FirstName" id="employee_FirstName" value="">
Notice that now the value is not inferred. Wah! I realize they are still developing heavily on this framework, but I thought I’d add some code that will do this for me. Here is an extension method you can add to your classes that will give you this desired functionality. Please note that this is VERY basic, and currently does not accept attributes. I will add it as I see the need:
public static string TextBox(this HtmlHelper helper, string name, string nothing)
{
string[] object_and_method = name.Split('.');
if (object_and_method.Length == 2)
{
// Get the ViewData object from the current view
object data = helper.ViewContext.ViewData;
// Get the particular property in question
var properties = from
property
in
data.GetType().GetProperties()
where
property.Name.ToLower() == object_and_method[1].ToLower()
select property;
// Find the first property that was returned above
// (there will only be one property with a given name)
var p = properties.First();
// Get the value from the ViewData object for the given property
object value_object = p.GetValue(data, null);
// Default to empty string if null (for new objects)
string value = value_object == null ? string.Empty : value_object.ToString();
// Return the TextBox HTML
return TextInputBuilder.TextBox(name, value, 20, 0, null);
}
return helper.TextBox(name, "", 20, 0, ((IDictionary<string, object>)null));
}
As I mentioned, this is an extension method. The existing TextBox methods are also implemented as extension methods on a class called TextInputExtensions. This class has a method with the signature:
public string TextBox(this HtmlHelper helper, string htmlName)
Unfortunately, this keeps me from being able to define my own method with the same signature, therefore I added the second string parameter called “nothing”; otherwise ASP.NET throws an exception saying that my method & the afore mentioned method are ambiguous. If anyone knows a way around this, please let me know.
This was very quickly coded, so I’m sure it could be a lot better. I just wanted to show one way my desired functionality could be achieved. If you have any comments, please email them to me as my comments aren’t very stable at this point in time (joe at faithfulgeek dot org). I’d love to hear some thoughts around this!
- Posted 3 months ago
- comments[0]
- Permalink
- Digg This!