You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RouteCollectionExtensions.cs 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. using System;
  2. using System.Linq.Expressions;
  3. using System.Web.Mvc;
  4. using System.Web.Routing;
  5. namespace Sdbarker.Extensions.RouteCollectionExtensions
  6. {
  7. public static class RouteCollectionExtensions
  8. {
  9. /// <summary>
  10. /// Maps a URL route and sets the default values.
  11. /// </summary>
  12. /// <typeparam name="TController"></typeparam>
  13. /// <param name="routes">The RouteCollection for this extension.</param>
  14. /// <param name="action">The method that this route will call on the specified controller.</param>
  15. /// <param name="name">Optional: A string that specifies the name of the route (automatically generated as ControllerMethod if null or empty)</param>
  16. /// <param name="url">Optional: A string that specifies the URL for the route (automatically generated as Controller/Method if null or empty)</param>
  17. /// <param name="defaults">Optional: An object that contains default route values.</param>
  18. /// <param name="constraints">Optional: An object that specifies the contraints of the route.</param>
  19. /// <param name="isDefaultRoute">Optional: Overrides the specified name and url parameters with the required values to make this route the default route ("Default" and "{Controller}/{Action}" respectively.)</param>
  20. /// <returns>The generated Route object.</returns>
  21. public static Route MapRoute<TController>(this RouteCollection routes, Expression<Func<TController, ActionResult>> action, string name = null, string url = null, object defaults = null, object constraints = null, bool isDefaultRoute = false) where TController : IController {
  22. MethodCallExpression m = (MethodCallExpression)action.Body;
  23. if (m.Method.ReturnType != typeof(ActionResult)) {
  24. throw new ArgumentException("ControllerAction method '" + m.Method.Name + "' does not return type ActionResult");
  25. }
  26. if (isDefaultRoute)
  27. {
  28. if (routes["Default"] != null) {
  29. throw new ArgumentException("Trying to create a new default route when a default route already exists.");
  30. }
  31. name = "Default";
  32. url = "{Controller}/{Action}";
  33. }
  34. else
  35. {
  36. if (string.IsNullOrEmpty(name)) {
  37. name = typeof(TController).Name + m.Method.Name;
  38. }
  39. if (string.IsNullOrEmpty(url)) {
  40. url = string.Format("{0}/{1}", typeof(TController).Name.RemoveLastInstanceOf("Controller"), m.Method.Name);
  41. }
  42. }
  43. if (defaults == null) {
  44. defaults = new { action = m.Method.Name };
  45. }
  46. else {
  47. defaults = new RouteValueDictionary(defaults);
  48. (defaults as RouteValueDictionary).Add("action", m.Method.Name);
  49. }
  50. return routes.MapRoute<TController>(name, url, defaults, constraints);
  51. }
  52. private static Route MapRoute<TController>(this RouteCollection routes, string name, string url, object defaults, object constraints) where TController : IController {
  53. Route route = new Route(url, new MvcRouteHandler()) {
  54. Defaults = (defaults is RouteValueDictionary) ? (defaults as RouteValueDictionary) : new RouteValueDictionary(defaults),
  55. Constraints = new RouteValueDictionary(constraints)
  56. };
  57. // If a controller property was specified in the defaults, argument exception; someone is doing something that they're not aware of
  58. string controller = typeof(TController).Name.RemoveLastInstanceOf("Controller");
  59. if (route.Defaults.ContainsKey("controller")) {
  60. throw new ArgumentException("Defaults contains key 'controller', but using a strongly typed route.");
  61. // route.Defaults["controller"] = controller;
  62. }
  63. route.Defaults.Add("controller", controller);
  64. // Move the original action (which is really a ControllerAction) to the controllerAction key
  65. // and then specify our own action value, otherwise routing will flip out
  66. object action;
  67. if (route.Defaults.TryGetValue("action", out action)) {
  68. if (action.GetType().IsGenericType && action.GetType().GetGenericTypeDefinition() == typeof(ControllerAction<>)) {
  69. route.Defaults.Add("controllerAction", route.Defaults["action"]);
  70. route.Defaults["action"] = route.Defaults["controllerAction"].ToString();
  71. }
  72. }
  73. routes.Add(name, route);
  74. return route;
  75. }
  76. }
  77. public class ControllerAction<TController> where TController : IController {
  78. public string Action { get; private set; }
  79. public override string ToString() {
  80. return Action;
  81. }
  82. public static implicit operator string(ControllerAction<TController> controllerAction) {
  83. return controllerAction.Action;
  84. }
  85. public ControllerAction(Expression<Func<TController, ActionResult>> action) {
  86. MethodCallExpression m = (MethodCallExpression)action.Body;
  87. if (m.Method.ReturnType != typeof(ActionResult)) {
  88. throw new ArgumentException("ControllerAction method '" + m.Method.Name + "' does not return type ActionResult");
  89. }
  90. Action = m.Method.Name;
  91. }
  92. }
  93. }