|
|||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article
IntroductionThis is article is a continuation of ASP.NET MVC Part 1 in which I will attempt to elaborate on the URL Routing portion of MVC. A word of caution though, the previous article was based on the Preview 2 release of ASP.NET MVC, however, this article uses the Preview 3 release. There are some things that have changed between these releases. PrerequisitesASP.NET 3.5 Extensions Review of Model-View-Controller PatternTo recap a little from the first part of this article, let’s briefly discuss the MVC pattern. MVC is a pattern that divides an application into separate areas of responsibility; Model, View and Controller. URL RoutingURL Routing is a part the MVC Web Application framework. However, Microsoft has chosen to also make it a part of the .Net Framework 3.5 Service Pack 1 though its functionality may of course differ from the implementation in MVC. We can take a look at how URL Routing is accomplished in MVC to get an understanding of how it may be implements in non-MVC web applications. The URL Routing components are, appropriately enough, in the
URL Routing makes use of Routing HTTPModuleAs brief review, <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule,
System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
As a word of caution, Preview 3 uses the follow to avoid conflicts with SP1 <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule,
System.Web.Routing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
RequestData data2 = new RequestData();
data2.OriginalPath = context.Request.Path;
data2.HttpHandler = httpHandler;
context.Items[_requestDataKey] = data2;
context.RewritePath("~/UrlRouting.axd");
Routing HttpHandlerAgain, as a brief review,are used simply to take requests and processes them. In the case of URL Routing, the will used to process requests coming from that we saw above. In the method of the an instance of the controller for the request being processed is attempted to be created from an instance and then the method called.
string controllerName = RequestContext.RouteData.GetRequiredString("controller");
// Instantiate the controller and call Execute
IControllerFactory factory = ControllerBuilder.GetControllerFactory();
IController controller = factory.CreateController(RequestContext, controllerName);
…
controller.Execute(controllerContext);
ControllerAs we saw in part 1, Controllers are like the middleware of ASP.NET MVC web application. They take the request for a certain action, do any processing, such as retrieving data from the model, then invoking a view. As described above, thefor the request is found then its method is called. In the method the for the request is found and attempted to be invoked
string actionName = RouteData.GetRequiredString("action");
if (!InvokeAction(actionName))
{
HandleUnknownAction(actionName);
}
The This is a brief look at the inner workings of the URL Routing mechanisms. A much more detailed review can be found here, http://www.cnblogs.com/shanyou/archive/2008/03/22/1117573.html Defining and Creating RoutesNow that we have an understanding of what is happening behind the scenes, we can now concentrate on creating and defining routes to be used in an application.
protected void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("Default", "{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" }
);
}
This is a default implementation for an ASP.NET MVC application. public static void IgnoreRoute(this RouteCollection routes, string url, object constraints)
{
if (routes == null)
{
throw new ArgumentNullException("routes");
}
if (url == null)
{
throw new ArgumentNullException("url");
}
Route route2 = new Route(url, new StopRoutingHandler());
route2.Constraints = new RouteValueDictionary(constraints);
Route item = route2;
routes.Add(item);
}
This method creates a new Route that uses the StopRoutingHandler to stop processing requests for HTTPHandlers. This is essential for processing request in MVC since, as we saw above, requests are redirected to UrlRouting.axd. Routes are added to the collection using MapRoute, which is an extension method to RouteCollection provided by MVC with three overrides.
public static void MapRoute(this RouteCollection routes, string name, string url)
public static void MapRoute(this RouteCollection routes, string name, string url, object defaults)
public static void MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints)
The first two overrides call the last, which creates a Route that uses the MvcRouteHandler then adds it to the collection.
Route route = new Route(url, new MvcRouteHandler())
{
Defaults = new RouteValueDictionary(defaults),
Constraints = new RouteValueDictionary(constraints)
};
if(String.IsNullOrEmpty(name))
{
// Add unnamed route if no name given
routes.Add(route);
}
else
{
routes.Add(name, route);
}
If a Route that did not use the MvcRouteHandler it could, of course, be added directly to the collection.
routes.Add(new Route("Default.aspx", new{ controller = "Home", action = "Index"}, new MyRouteHandler);
Routing in actionWith URL Routing you can accept requests such as http://www.mysite.com/Products/Bikes/Schwinn, and have it, for instance, display all bikes made by Schwinn. Rather than using query string parameters this produces a much cleaner URL and routing details can be hidden from ordinary users. ASP.NET MVC expects URLs to have at least two elements, Route("{controller/{action}",
new RouteValueDictionary( new { controller = "Home", action = "Index" }),
new MvcRouteHandler());
The first parameter is the URL pattern to match requests against. The second parameter is a RouteValueDictionary that can be used to provide default values if not found in the requested URL. In the case of a request for http://www.mysite.com would be rewritten as http://www.mysite.com/Home/Index. A request for http://www.mysite.com/Home would also be rewritten as http://www.mysite.com/Home/Index
routes.MapRoute("DefaultRoute", "{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = 0 }
);
routes.MapRoute("NameRoute", "Artist/{name}",
new { controller = "Music", action = "ArtistsByName", name = "AC/DC" }
);
A URL such as http://www.mysite.com/Artist/Elvis will be matched by the first route despite it having the word Artist. The first Route assumes that Artist is meant to be the controller and Elvis the action, a default id of 0 will be inserted. To get the desired results, the Routes need to be reversed in the collection. Given the two Routes below the problem is determining which is used for requests such as http://www.mysite.com/Artist/1394 and http://www.mysite.com/Artist/U2
routes.MapRoute("ArtistByID", "Artist/{id}",
new { controller = "Artist", action = "AlbumsByArtistId", id = 0 }
);
routes.MapRoute("ArtistByName", "Artist/{name}",
new { controller = "Artist", action = "AlbumsByArtistName", name = "" }
);
In the former URL it’s obvious that what is being provided is an ID, however, in the letter URL U2 is assumed by the engine to be an ID and will attempt to case it to an integer as required by the AlbumsByArtistId action method. If the Routes were reversed, 1394 would be converted to string as required by AlbumsByArtistName. To solve this problem we can make use of the Constraints parameter when creating the Route. This parameter is a RouteValueDictionary that is used to a Regular Expressions to be used to evaluate a specified parameter in the requested URL.
protected virtual bool ProcessConstraint(HttpContextBase httpContext, object constraint,
string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
object obj2;
IRouteConstraint constraint2 = constraint as IRouteConstraint;
if (constraint2 != null)
{
return constraint2.Match(httpContext, this, parameterName, values, routeDirection);
}
string str = constraint as string;
if (str == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture,
RoutingResources.Route_ValidationMustBeStringOrCustomConstraint,
new object[] { parameterName, this.Url }));
}
values.TryGetValue(parameterName, out obj2);
string input = Convert.ToString(obj2, CultureInfo.InvariantCulture);
string pattern = "^(" + str + ")$";
return Regex.IsMatch(input, pattern, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
}
The above Routes can be modified as follows
routes.MapRoute("ArtistByID", "Artist/{id}",
new { controller = "Artist", action = "AlbumsByArtistId", id = 0 },
new { id = @"\d{1,}" }
);
routes.MapRoute("ArtistByName", "Artist/{name}",
new { controller = "Artist", action = "AlbumsByArtistName", name = "" },
new { name = @"[a-zA-Z]{1,}" }
);
Now the request for http://www.mysite.com/Artist/1394 will be evaluated as matching the ArtistByID Route and http://www.mysite.com/Artist/U2 by the ArtistByName Route regardless of the order they appear in the RouteTable.
To be continued…ASP.NET MVC is a very rich technology that can’t be covered in a single article. Hopefully this article has illustrated the basic concepts and can be used to evaluate the potential of this technology. Future articles in this series will cover a more aspects such as unit testing and forms.Referenceshttp://www.asp.net/downloads/3.5-extensions/http://weblogs.asp.net/scottgu/archive/2007/10/14/asp-net-mvc-framework.aspx
|
||||||||||||||||||||||||||||||||||||||||||||||