Wednesday, September 29, 2010

Asp.Net 4 - URL Routing (1)

ASP.NET 4 brings in a new feature - URL routing. Similar to that in the MVC framework, with which we can easily implement search engine-friendly URLs. Search engine-friendly URLs is part of what is called SEO - Search Engine Optimization, something that a web application desires.

1. The API.
To use URL routing, I need to add reference to system.web.routing.dll, and import the namespace System.Web.Routing (shown in below code).

using System;
using System.Web.Routing;

/// <summary>
/// Summary description for Global
/// </summary>
public class Global : System.Web.HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.MapPageRoute("SearchRoute1", "search", "~/default.aspx");
RouteTable.Routes.MapPageRoute("SearchRoute", "search/{searchterm}", "~/default.aspx");
RouteTable.Routes.MapPageRoute("SearchRoute2", "search/{searchterm}/{s2}", "~/default.aspx");
RouteTable.Routes.MapPageRoute("SearchRoute3", "about/", "~/about.aspx");
RouteTable.Routes.MapPageRoute("SearchRoute6", "about/{year}/{p1}", "~/about.aspx");
}
}

Now that I have set up the mapping table, I need to register it. The perfect place to do so is the global.asax. Following code lets the Application inherit from my custom Global class, then my Application_Start event handler in Global gets hooked when the application starts up running.

<%@ Application Language="C#" Inherits="Global" %>

2. Access url parameters

With routing, how can I get the query variables that I would get from query string in case of no routing? In routing environment, the parameters that come along with a request are stored in RouteData.Values collection, as shown below.

using System;
using System.Web.Routing;

public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Response.Write(Page.RouteData.Values["searchterm"] as string);
Response.Write(Page.RouteData.Values["s2"] as string);
}
}

In case the requested entry is not exist, it returns null.

3. Specify url and parameters from the markup

A common scenario, in markup I create links using routing URL. As shown in following control.

<asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl="<%$RouteUrl:SearchTerm=scott%>">Search for Scott</asp:HyperLink>

In it, a link is represented by a RouteUrl Expression. For a link with multiple parameters, use "," to separate, as shown in following code.
<%$RouteUrl:p1=value1, p2=value2..., routename=UserRoute %>

When routename specified, it goes to that route and try to match with the parameters, in case not match, it raise "unfound resource" exception. If routename is not specified, it matches the current(requested) url with the parameters.

The mapping is a uni-direction mapping, instead of bi-direction mapping. If I give a url in traditional style, then it just goes to the file, rather than map to search engine-friendly url.

The matching of parameters is strict. If a exact match of parameters in number and names not exist, it fails.

In markup, We can directly provide the url as following, why need RouteUrl Expression?

<asp:HyperLink ID="HyperLink2" runat="server"
NavigateUrl="~/salesreport/WA/2011">
Sales Report - WA, 2011
</asp:HyperLink>

With $RouteUrl, for one thing, I don't need to care about parameter orders, because, the parameters are named, rather than anonymous.

4. Route Patten Constraints

I can apply certain rules on a route pattern, e.g. apply constraint on parameters, ignore some routes etc. Following demonstrates of different types of constraints.

A. The General RoutePatten
SalesReport/{locale}/{year}

B. Routes.Ignore - to igore matching to some pattern
routes.Ignore("{resource}.axd/{*pathInfo}");

C. catch-all parameter - define optional parameters
ExpenseReport/{locale}/{year}/{*extrainfo}

D. Route Parameter Value Constraint
Specify constraints on routing parameter values:
routes.MapPageRoute("",
"Category/{action}/{categoryName}", "~/categoriespage.aspx", true,
new RouteValueDictionary
{{"categoryName", "food"}, {"action", "show"}},
new RouteValueDictionary
{{"locale", "[a-z]{2}-[a-z]{2}"},{"year", @"\d{4}"}}
);

E. Default Value for Parameters
Above code also specified default values for parameters while delaring a route map.

Use of default value is very tricky. Because default value collection may have parameters that are not defined in the URL, if I specify a that sort of paramter, then I have to give the value same as the default, otherwise it will be a failure to mismatch.

No comments: