ASP.NET MVC Routing Via Method Attributes [closed]
Solution 1:
UPDATE: This has been posted on codeplex. The complete source code as well as the pre-compiled assembly are there for download. I haven't had time to post the documentation on the site yet, so this SO post will have to suffice for now.
UPDATE: I added some new attributes to handle 1) route ordering, 2) route parameter constraints, and 3) route parameter default values. The text below reflects this update.
I've actually done something like this for my MVC projects (I have no idea how Jeff is doing it with stackoverflow). I defined a set of custom attributes: UrlRoute, UrlRouteParameterConstraint, UrlRouteParameterDefault. They can be attached to MVC controller action methods to cause routes, constraints, and defaults to be bound to them automatically.
Example usage:
(Note this example is somewhat contrived but it demonstrates the feature)
public class UsersController : Controller
{
// Simple path.
// Note you can have multiple UrlRoute attributes affixed to same method.
[UrlRoute(Path = "users")]
public ActionResult Index()
{
return View();
}
// Path with parameter plus constraint on parameter.
// You can have multiple constraints.
[UrlRoute(Path = "users/{userId}")]
[UrlRouteParameterConstraint(Name = "userId", Regex = @"\d+")]
public ActionResult UserProfile(int userId)
{
// ...code omitted
return View();
}
// Path with Order specified, to ensure it is added before the previous
// route. Without this, the "users/admin" URL may match the previous
// route before this route is even evaluated.
[UrlRoute(Path = "users/admin", Order = -10)]
public ActionResult AdminProfile()
{
// ...code omitted
return View();
}
// Path with multiple parameters and default value for the last
// parameter if its not specified.
[UrlRoute(Path = "users/{userId}/posts/{dateRange}")]
[UrlRouteParameterConstraint(Name = "userId", Regex = @"\d+")]
[UrlRouteParameterDefault(Name = "dateRange", Value = "all")]
public ActionResult UserPostsByTag(int userId, string dateRange)
{
// ...code omitted
return View();
}
Definition of UrlRouteAttribute:
/// <summary>
/// Assigns a URL route to an MVC Controller class method.
/// </summary>
[AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class UrlRouteAttribute : Attribute
{
/// <summary>
/// Optional name of the route. If not specified, the route name will
/// be set to [controller name].[action name].
/// </summary>
public string Name { get; set; }
/// <summary>
/// Path of the URL route. This is relative to the root of the web site.
/// Do not append a "/" prefix. Specify empty string for the root page.
/// </summary>
public string Path { get; set; }
/// <summary>
/// Optional order in which to add the route (default is 0). Routes
/// with lower order values will be added before those with higher.
/// Routes that have the same order value will be added in undefined
/// order with respect to each other.
/// </summary>
public int Order { get; set; }
}
Definition of UrlRouteParameterConstraintAttribute:
/// <summary>
/// Assigns a constraint to a route parameter in a UrlRouteAttribute.
/// </summary>
[AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class UrlRouteParameterConstraintAttribute : Attribute
{
/// <summary>
/// Name of the route parameter on which to apply the constraint.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Regular expression constraint to test on the route parameter value
/// in the URL.
/// </summary>
public string Regex { get; set; }
}
Definition of UrlRouteParameterDefaultAttribute:
/// <summary>
/// Assigns a default value to a route parameter in a UrlRouteAttribute
/// if not specified in the URL.
/// </summary>
[AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class UrlRouteParameterDefaultAttribute : Attribute
{
/// <summary>
/// Name of the route parameter for which to supply the default value.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Default value to set on the route parameter if not specified in the URL.
/// </summary>
public object Value { get; set; }
}
Changes to Global.asax.cs:
Replace calls to MapRoute, with a single call to the RouteUtility.RegisterUrlRoutesFromAttributes function:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
RouteUtility.RegisterUrlRoutesFromAttributes(routes);
}
Definition of RouteUtility.RegisterUrlRoutesFromAttributes:
The full source is up on codeplex. Please go to the site if you have any feedback or bug reports.
Solution 2:
You can also try AttributeRouting, which is available from github or via nuget.
This is a shameless plug, as I am the project author. But dang if I'm not very happy using it. You might be too. There is plenty of documentation and sample code in the github repository wiki.
With this library, you can do a lot:
- Decorate your actions with GET, POST, PUT, and DELETE attributes.
- Map multiple routes to a single action, ordering them with an Order property.
- Specify route defaults and constraints using attributes.
- Specify optional params with a simple ? token before the parameter name.
- Specify the route name for supporting named routes.
- Define MVC areas on a controller or base controller.
- Group or nest your routes together using route prefixes applied to a controller or base controller.
- Support legacy urls.
- Set the precedence of routes among the routes defined for an action, within a controller, and among controllers and base controllers.
- Generate lowercase outbound urls automatically.
- Define your own custom route conventions and apply them on a controller to generate the routes for actions within the controller without boilerplate attributes (think RESTful style).
- Debug your routes using a supplied HttpHandler.
I'm sure there's some other stuff I'm forgetting. Check it out. It's painless to install via nuget.
NOTE: As of 4/16/12, AttributeRouting also supports the new Web API infrastructure. Just in case you're looking for something that can handle that. Thanks subkamran!