For a scenario, I have a ASP.NET MVC application with URLs that look like the following:
http://example.com/Customer/List
http://example.com/Customer/List/Pa
You can create a route that is constrained to only match actions in your Customer controller.
public static class RoutingExtensions {
///Creates a route that maps URLs without a controller to action methods in the specified controller
///The controller type to map the URLs to.
public static void MapDefaultController(this RouteCollection routes) where TController : ControllerBase {
routes.MapControllerActions(typeof(TController).Name, "{action}/{id}", new { action = "Index", id = UrlParameter.Optional });
}
///Creates a route that only matches actions from the given controller.
///The controller type to map the URLs to.
public static void MapControllerActions(this RouteCollection routes, string name, string url, object defaults) where TController : ControllerBase {
var methods = typeof(TController).GetMethods()
.Where(m => !m.ContainsGenericParameters)
.Where(m => !m.IsDefined(typeof(ChildActionOnlyAttribute), true))
.Where(m => !m.IsDefined(typeof(NonActionAttribute), true))
.Where(m => !m.GetParameters().Any(p => p.IsOut || p.ParameterType.IsByRef))
.Select(m => m.GetActionName());
routes.Add(name, new Route(url, new MvcRouteHandler()) {
Defaults = new RouteValueDictionary(defaults) { { "controller", typeof(TController).Name.Replace("Controller", "") } },
Constraints = new RouteValueDictionary { { "action", new StringListConstraint(methods) } }
});
}
private static string GetActionName(this MethodInfo method) {
var attr = method.GetCustomAttribute();
if (attr != null)
return attr.Name;
return method.Name;
}
class StringListConstraint : IRouteConstraint {
readonly HashSet validValues;
public StringListConstraint(IEnumerable values) { validValues = new HashSet(values, StringComparer.OrdinalIgnoreCase); }
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) {
return validValues.Contains(values[parameterName]);
}
}
#region GetCustomAttributes
///Gets a custom attribute defined on a member.
///The type of attribute to return.
///The object to get the attribute for.
///The first attribute of the type defined on the member, or null if there aren't any
public static TAttribute GetCustomAttribute(this ICustomAttributeProvider provider) where TAttribute : Attribute {
return provider.GetCustomAttribute(false);
}
///Gets the first custom attribute defined on a member, or null if there aren't any.
///The type of attribute to return.
///The object to get the attribute for.
///Whether to look up the hierarchy chain for attributes.
///The first attribute of the type defined on the member, or null if there aren't any
public static TAttribute GetCustomAttribute(this ICustomAttributeProvider provider, bool inherit) where TAttribute : Attribute {
return provider.GetCustomAttributes(inherit).FirstOrDefault();
}
///Gets the custom attributes defined on a member.
///The type of attribute to return.
///The object to get the attribute for.
public static TAttribute[] GetCustomAttributes(this ICustomAttributeProvider provider) where TAttribute : Attribute {
return provider.GetCustomAttributes(false);
}
///Gets the custom attributes defined on a member.
///The type of attribute to return.
///The object to get the attribute for.
///Whether to look up the hierarchy chain for attributes.
public static TAttribute[] GetCustomAttributes(this ICustomAttributeProvider provider, bool inherit) where TAttribute : Attribute {
if (provider == null) throw new ArgumentNullException("provider");
return (TAttribute[])provider.GetCustomAttributes(typeof(TAttribute), inherit);
}
#endregion
}