Export (0) Print
Expand All

ASP.NET Routing

ASP.NET routing enables you to use URLs that do not have to map to specific files in a Web site. Because the URL does not have to map to a file, you can use URLs that are descriptive of the user's action and therefore are more easily understood by users.

The ASP.NET MVC framework and ASP.NET Dynamic Data extend routing to provide features that are used only in MVC applications and in Dynamic Data applications. For more information about MVC, see ASP.NET MVC 3. For more information about Dynamic Data, see ASP.NET Dynamic Data Content Map.

In an ASP.NET application that does not use routing, an incoming request for a URL typically maps to a physical file that handles the request, such as an .aspx file. For example, a request for http://server/application/Products.aspx?id=4 maps to a file that is named Products.aspx that contains code and markup for rendering a response to the browser. The Web page uses the query string value of id=4 to determine what type of content to display.

In ASP.NET routing, you can define URL patterns that map to request-handler files, but that do not necessarily include the names of those files in the URL. In addition, you can include placeholders in a URL pattern so that variable data can be passed to the request handler without requiring a query string.

For example, in the request for http://server/application/Products/show/beverages, the routing parser can pass the values Products, show, and beverages to the page handler. In this example, if the route is defined by using the URL pattern server/application/{area}/{action}/{category}, the page handler would receive a dictionary collection in which the value associated with the key area is Products, the value for the key action is show, and the value for the key category is beverages. In a request that is not managed by URL routing, the /Products/show/beverages fragment would be interpreted as the path of a file in the application.

This topic contains the following sections:

A route is a URL pattern that is mapped to a handler. The handler can be a physical file, such as an .aspx file in a Web Forms application. A handler can also be a class that processes the request, such as a controller in an MVC application. To define a route, you create an instance of the Route class by specifying the URL pattern, the handler, and optionally a name for the route.

You add the route to the application by adding the Route object to the static Routes property of the RouteTable class. The Routes property is a RouteCollection object that stores all the routes for the application.

You typically do not have to write code to add routes in an MVC application. Visual Studio project templates for MVC include preconfigured URL routes. These are defined in the MvcApplication class, which is defined in the Global.asax file.

A URL pattern can contain literal values and variable placeholders (referred to as URL parameters). The literals and placeholders are located in segments of the URL which are delimited by the slash (/) character.

When a request is made, the URL is parsed into segments and placeholders, and the variable values are provided to the request handler. This process is similar to the way the data in query strings is parsed and passed to the request handler. In both cases variable information is included in the URL and passed to the handler in the form of key-value pairs. For query strings both the keys and the values are in the URL. For routes, the keys are the placeholder names defined in the URL pattern, and only the values are in the URL.

In a URL pattern, you define placeholders by enclosing them in braces ( { and } ). You can define more than one placeholder in a segment, but they must be separated by a literal value. For example, {language}-{country}/{action} is a valid route pattern. However, {language}{country}/{action} is not a valid pattern, because there is no literal value or delimiter between the placeholders. Therefore, routing cannot determine where to separate the value for the language placeholder from the value for the country placeholder.

The following table shows valid route patterns and examples of URL requests that match the patterns.

Route definition

Example of matching URL

{controller}/{action}/{id}

/Products/show/beverages

{table}/Details.aspx

/Products/Details.aspx

blog/{action}/{entry}

/blog/show/123

{reporttype}/{year}/{month}/{day}

/sales/2008/1/5

{locale}/{action}

/US/show

{language}-{country}/{action}

/en-US/show

Typical URL Patterns in MVC Applications

URL patterns for routes in MVC applications typically include {controller} and {action} placeholders.

When a request is received, it is routed to the UrlRoutingModule object and then to the MvcHandler HTTP handler. The MvcHandler HTTP handler determines which controller to invoke by adding the suffix "Controller" to the controller value in the URL to determine the type name of the controller that will handle the request. The action value in the URL determines which action method to call.

For example, a URL that includes the URL path /Products is mapped to a controller named ProductsController. The value in the action parameter is the name of the action method that is called. A URL that includes the URL path /Products/show would result in a call to the Show method of the ProductsController class.

The following table shows the default URL patterns, and it shows examples of URL requests that are handled by the default routes.

Default URL pattern

Examples of matching URL

{controller}/{action}/{id}

http://server/application/Products/show/beverages

{resource}.axd/{*pathInfo}

http://server/application/WebResource.axd?d=...

The route with the pattern {resource}.axd/{*pathInfo} is included to prevent requests for the Web resource files such as WebResource.axd or ScriptResource.axd from being passed to a controller.

For IIS 7.0, no file-name extension is needed. For IIS 6.0, you must add the .mvc file-name extension to the URL pattern, as in the following example:

{controller}.mvc/{action}/{id}

In a Web Forms application, you create routes by using the MapPageRoute(String, String, String) method of the RouteCollection class. The MapPageRoute method creates a Route object and adds it to the RouteCollection object. You specify properties for the Route object in parameters that you pass to the MapPageRoute method.

Typically, you add routes in a method that is called from the handler for the Application_Start event in the Global.asax file. This approach makes sure that the routes are available when the application starts. It also enables you to call the method directly when you unit-test the application. If you want to call a method directly when you unit-test the application, the method that registers the routes must be static (Shared in Visual Basic) and must have a RouteCollection parameter.

The following example shows code from a Global.asax file that adds a Route object that defines two URL parameters named action and categoryName. URLs that have the specified pattern are directed to the physical page named Categories.aspx.

protected void Application_Start(object sender, EventArgs e)
{
    RegisterRoutes(RouteTable.Routes);
}

public static void RegisterRoutes(RouteCollection routes)
{
    routes.MapPageRoute("",
        "Category/{action}/{categoryName}",
        "~/categoriespage.aspx");
}

If you adopt the MVC convention of implementing controllers by creating classes that derive from the ControllerBase class and giving them names that end with "Controller", you do not need to manually add routes in an MVC application. The preconfigured routes will invoke the action methods that you implement in the controller classes.

If you want to add custom routes in an MVC application, you use the MapRoute(RouteCollection, String, String) method instead of the MapPageRoute(String, String, String) method.

The following example shows the code that creates default MVC routes in the Global.asax file, as defined in the Visual Studio project template for MVC applications.


public class MvcApplication : System.Web.HttpApplication
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            "Default",                                              // Route name
            "{controller}/{action}/{id}",                           // URL with parameters
            new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
        );

    }

    protected void Application_Start()
    {
        RegisterRoutes(RouteTable.Routes);
    }
}


When you define a route, you can assign a default value for a parameter. The default value is used if a value for that parameter is not included in the URL. You set default values for a route by assigning a dictionary object to the Defaults property of the Route class. The following example shows how to add a route that has default values, by using the MapPageRoute(String, String, String, Boolean, RouteValueDictionary) method.

void Application_Start(object sender, EventArgs e) 
{
    RegisterRoutes(RouteTable.Routes);
}

public static void RegisterRoutes(RouteCollection routes)
{
    routes.MapPageRoute("",
        "Category/{action}/{categoryName}",
        "~/categoriespage.aspx",
        true,
        new RouteValueDictionary 
            {{"categoryName", "food"}, {"action", "show"}});
}

When ASP.NET routing handles a URL request, the route definition shown in the example (with default values of food for categoryName and show for action) produces the results that are listed in the following table.

URL

Parameter values

/Category

action = "show" (default value)

categoryName = "food" (default value)

/Category/add

action = "add"

categoryName = "food" (default value)

/Category/add/beverages

action = "add"

categoryName= "beverages"

For MVC applications, overloads of the RouteCollectionExtensions.MapRoute method, such as MapRoute(RouteCollection, String, String, Object, Object), enable you to specify defaults.

Sometimes you have to handle URL requests that contain a variable number of URL segments. When you define a route, you can specify that if a URL has more segments than there are in the pattern, the extra segments are considered to be part of the last segment. To handle additional segments in this manner you mark the last parameter with an asterisk (*). This is referred to as a catch-all parameter. A route with a catch-all parameter will also match URLs that do not contain any values for the last parameter. The following example shows a route pattern that matches an unknown number of segments.

query/{queryname}/{*queryvalues}

When ASP.NET routing handles a URL request, the route definition shown in the example produces the results that are listed in the following table.

URL

Parameter values

/query/select/bikes/onsale

queryname = "select"

queryvalues = "bikes/onsale"

/query/select/bikes

queryname = "select"

queryvalues = "bikes"

/query/select

queryname = "select"

queryvalues = Empty string

In addition to matching a URL request to a route definition by the number of parameters in the URL, you can specify that values in the parameters meet certain constraints. If a URL contains values that are outside the constraints for a route, that route is not used to handle the request. You add constraints to make sure that the URL parameters contain values that will work in your application.

Constraints are defined by using regular expressions or by using objects that implement the IRouteConstraint interface. When you add the route definition to the Routes collection, you add constraints by creating a RouteValueDictionary object that contains the verification test. The key in the dictionary identifies the parameter that the constraint applies to. The value in the dictionary can be either a string that represents a regular expression or an object that implements the IRouteConstraint interface.

If you provide a string, routing treats the string as a regular expression and checks whether the parameter value is valid by calling the IsMatch method of the Regex class. The regular expression is always treated as case-insensitive. For more information, see .NET Framework Regular Expressions.

If you provide an IRouteConstraint object, ASP.NET routing checks whether the parameter value is valid by calling the Match method of the IRouteConstraint object. The Match method returns a Boolean value that indicates whether the parameter value is valid.

The following example shows how to use the MapPageRoute method to create a route that has constraints that limit what values can be included in the locale and year parameters. (In an MVC application, you would use the MapRoute method.)

public static void RegisterRoutes(RouteCollection routes)
{
    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}"}}
       );
}

When routing handles a URL request, the route definition shown in the previous example produces the results that are listed in the following table.

URL

Result

/US

No match. Both locale and year are required.

/US/08

No match. The constraint on year requires 4 digits.

/US/2008

locale = "US"

year = "2008"

Under some circumstances, ASP.NET routing does not handle a request even when is enabled for the Web site. This section describes some scenarios in which routing does not handle the request.

A Physical File is Found that Matches the URL Pattern

By default, routing does not handle requests that map to an existing physical file on the Web server. For example, a request for http://server/application/Products/Beverages/Coffee.aspx is not handled by routing if a physical file exists at Products/Beverages/Coffee.aspx. Routing does not handle the request even if it matches a defined pattern, such as {controller}/{action}/{id}.

If you want routing to handle all requests, even requests that point to files, you can override the default behavior by setting the RouteExistingFiles property of the RouteCollection object to true. When you set this value to true, all requests that match a defined pattern are handled by routing.

Routing Is Explicitly Disabled for a URL Pattern

You can also specify that routing should not handle certain URL requests. You prevent routing from handling certain requests by defining a route and specifying that the StopRoutingHandler class should be used to handle that pattern. When a request is handled by a StopRoutingHandler object, the StopRoutingHandler object blocks any additional processing of the request as a route. Instead, the request is processed as an ASP.NET page, Web service, or other ASP.NET endpoint. You can use the RouteCollection.Ignore method (or RouteCollectionExtensions.IgnoreRoute for MVC applications) to create routes that use the StopRoutingHandler class. The following example shows how to prevent routing from handling requests for the WebResource.axd file.

public static void RegisterRoutes(RouteCollection routes)
{
  routes.Ignore("{resource}.axd/{*pathInfo}");
}

When routing handles URL requests, it tries to match the URL of the request to a route. Matching a URL request to a route depends on all the following conditions:

  • The route patterns that you have defined or the default route patterns, if any, that are included in your project type.

  • The order in which you added them to the Routes collection.

  • Any default values that you have provided for a route.

  • Any constraints that you have provided for a route.

  • Whether you have defined routing to handle requests that match a physical file.

To avoid having the wrong handler handle a request, you must consider all these conditions when you define routes. The order in which Route objects appear in the Routes collection is significant. Route matching is tried from the first route to the last route in the collection. When a match occurs, no more routes are evaluated. In general, add routes to the Routes property in order from the most specific route definitions to least specific ones.

For example, suppose that you add routes with the following patterns:

  • Route 1 is set to {controller}/{action}/{id}

  • Route 2 is set to products/show/{id}

Route 2 will never handle a request because Route 1 is evaluated first, and it will always match requests that could also work for Route 2. A request for http://server/application/products/show/bikes seems to match Route 2 more closely, but it is handled by Route 1 with the following values:

  • controller is products.

  • action is show.

  • id is bikes.

Default values are used if a parameter is missing from the request. Therefore, they can cause a route to match a request that you did not expect. For example, suppose that you add routes with the following patterns:

  • Route 1: {report}/{year}/{month}, with default values for year and month.

  • Route 2: {report}/{year}, with a default value for year.

Route 2 will never handle a request. Route 1 might be intended for a monthly report, and Route 2 might be intended for an annual report. However, the default values in Route 1 mean that it will match any request that could also work for Route 2.

You can avoid ambiguity in the patterns by including constants, such as annual/{report}/{year} and monthly/{report}/{year}/{month}.

If a URL does not match any Route object that is defined in the RouteTable collection, ASP.NET routing does not process the request. Instead, processing is passed to an ASP.NET page, Web service, or other ASP.NET endpoint.

If you want to create hyperlinks to pages in your site, you can use the URL patterns to programmatically create URLs that correspond to the routes. When you change the patterns, URLs matching the new patterns will be generated automatically. For information about how to generate URLs in code or in markup, see How to: Construct URLs from Routes.

In the handler for a routed page request you can access the values that are passed in the URL placeholders by using code or markup. For more information, see How to: Access URL Parameters in a Routed Page.

For MVC applications, the MVC framework automatically handles the values passed in URL placeholders. For more information, see Passing Data in an ASP.NET MVC Application.

In ASP.NET, you can add the following configuration setting to applications in order to support routing:

<configuration>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <!-- more -->
    </modules>
  </system.webServer>
</configuration>

When runAllManagedModulesForAllRequests is true, a URL like http://mysite/myapp/home goes to ASP.NET, even though there is no .aspx, .mvc, or similar extension on the URL.

However, an update that was made to IIS 7 makes the runAllManagedModulesForAllRequests setting unnecessary and supports ASP.NET routing natively. (For information about the update, see the Microsoft Support article An update is available that enables certain IIS 7.0 or IIS 7.5 handlers to handle requests whose URLs do not end with a period.)

If your website is running on IIS 7 and if IIS has been updated, you do not need to set runAllManagedModulesForAllRequests to true. In fact, setting it to true is not recommended, because it adds unnecessary processing overhead to request. When this setting is true, all requests, including those for .htm, .jpg, and other static files, also go through the ASP.NET request pipeline.

The default setting for runAllManagedModulesForAllRequests is false. If the site's configuration file does not explicitly set runAllManagedModulesForAllRequests to true, when you then run the website on Windows 7 without SP1 installed, IIS 7 will not include the required update. As a consequence, routing will not work and you will see errors. If you have a problem where routing does not work, you can do the following:

  • Update Windows 7 to SP1, which will add the update to IIS 7.

  • Install the update that's described in the Microsoft Support article listed previously.

  • Set runAllManagedModulesForAllRequests to true in that website's Web.config file. Note that this will add some overhead to requests.

Authorization rules can be applied to only the route URL or to both the route URL and to the physical URL that it maps to. For example, authorization rules might specify that all users can access URLs that begin with Category but only administrators can access the Categories.aspx page. If the route URL pattern contoso.com/Category/{controller}/{action} maps to the physical URL contoso.com/Categoriespage.aspx, and you apply authorization rules only to the route URL, all users will be allowed access to Categoriespage.aspx when it is requested by using a route URL. However, only administrators will have access to it when it is requested by using a physical URL.

By default, authorization rules are applied to both route URL and physical URL. For more information, see the PageRouteHandler.CheckPhysicalUrlAccess property.

ASP.NET Web Forms and Route Security

In an ASP.NET Web Forms application, you should not depend solely on route authorization rules to secure your site, because that might leave some physical URLs unprotected.

ASP.NET MVC and Route Security

You cannot use routing or web.config files to secure an MVC application. The only supported way to secure an MVC application is to apply the AuthorizeAttribute attribute to each controller and use the AllowAnonymousAttribute attribute on the login and register actions. For more information, see Securing your ASP.NET MVC 4 App and the new AllowAnonymous Attribute on Rick Anderson's blog. To secure an ASP.NET MVC 3 application, see Securing your ASP.NET MVC 3 Application, also on Rick Anderson's blog.

The following table lists the key server classes for ASP.NET routing.

Class

Description

Route

Represents a route in a Web Forms or MVC application.

DynamicDataRoute

Represents a route in a Dynamic Data application.

RouteBase

Serves as the base class for all classes that represent an ASP.NET route.

RouteTable

Stores the routes for an application.

RouteCollection

Provides methods that enable you to manage a collection of routes.

RouteCollectionExtensions

Provides additional methods that enable you to manage a collection of routes in MVC applications.

RouteData

Contains the values for a requested route.

RequestContext

Contains information about the HTTP request that corresponds to a route.

StopRoutingHandler

Provides a way to specify that ASP.NET routing should not handle requests for a URL pattern.

PageRouteHandler

Provides a way to define routes for Web Forms applications.

RouteValueDictionary

Provides a way to store route Constraints, Defaults, and DataTokens objects.

VirtualPathData

Provides a way to generate URLs from route information.

ASP.NET routing differs from URL rewriting. URL rewriting processes incoming requests by actually changing the URL before it sends the request to the Web page. For example, an application that uses URL rewriting might change a URL from /Products/Widgets/ to /Products.aspx?id=4. Also, URL rewriting typically does not have an API for creating URLs that are based on your patterns. In URL rewriting, if you change a URL pattern, you must manually update all hyperlinks that contain the original URL.

With ASP.NET routing, the URL is not changed when an incoming request is handled, because routing can extract values from the URL. When you have to create a URL, you pass parameter values into a method that generates the URL for you. To change the URL pattern, you change it in one location, and all the links that you create in the application that are based on that pattern will automatically use the new pattern.

Community Additions

ADD
Show:
© 2014 Microsoft