/ToMigrate/Raven.Database/Server/WebApi/RouteCacher.cs

https://github.com/fitzchak/ravendb · C# · 216 lines · 167 code · 44 blank · 5 comment · 19 complexity · 33f9f8a76280871d5f448ce9acf53ad2 MD5 · raw file

  1. // -----------------------------------------------------------------------
  2. // <copyright file="RavenRouteCacher.cs" company="Hibernating Rhinos LTD">
  3. // Copyright (c) Hibernating Rhinos LTD. All rights reserved.
  4. // </copyright>
  5. // -----------------------------------------------------------------------
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Linq;
  9. using System.Reflection;
  10. using System.Web.Http;
  11. using System.Web.Http.Controllers;
  12. using System.Web.Http.Routing;
  13. namespace Raven.Database.Server.WebApi
  14. {
  15. public static class RouteCacher
  16. {
  17. private const string ActionsDataTokenKey = "actions";
  18. private const string InfoDataTokenKey = "info";
  19. private static Dictionary<string, HttpRouteInformation> routeCache;
  20. public static void ClearCache()
  21. {
  22. routeCache = null;
  23. }
  24. internal static void CacheRoutesIfNecessary(HttpConfiguration cfg)
  25. {
  26. if (routeCache != null)
  27. return;
  28. var cache = new Dictionary<string, HttpRouteInformation>();
  29. for (var i = 0; i < cfg.Routes.Count; i++)
  30. {
  31. var j = 0;
  32. var route = cfg.Routes[i];
  33. foreach (var routeInformation in CacheRoutes(route))
  34. {
  35. cache.Add(string.Format("RavenDB_Route_{0}_{1}", i, j), routeInformation);
  36. j++;
  37. }
  38. }
  39. routeCache = cache;
  40. }
  41. internal static bool TryAddRoutesFromCache(HttpConfiguration cfg)
  42. {
  43. var cache = routeCache;
  44. if (cache == null)
  45. return false;
  46. var previousInitializer = cfg.Initializer;
  47. cfg.Initializer = config =>
  48. {
  49. previousInitializer(config);
  50. var controllerDescriptors = new Dictionary<Type, HttpControllerDescriptor>();
  51. foreach (var pair in cache)
  52. {
  53. var name = pair.Key;
  54. var route = pair.Value;
  55. cfg.Routes.Add(name, RebuildRoutes(route, cfg, controllerDescriptors));
  56. }
  57. };
  58. return true;
  59. }
  60. private static IHttpRoute RebuildRoutes(HttpRouteInformation routeInformation, HttpConfiguration cfg, Dictionary<Type, HttpControllerDescriptor> controllerDescriptors)
  61. {
  62. var routeCollectionInformation = routeInformation as HttpRouteCollectionInformation;
  63. if (routeCollectionInformation != null)
  64. {
  65. var routes = routeCollectionInformation
  66. .Routes
  67. .Select(innerRoute => RebuildRouteInternal(innerRoute, cfg, controllerDescriptors))
  68. .ToList();
  69. return new RavenRouteCollectionRoute(routes);
  70. }
  71. return RebuildRouteInternal(routeInformation, cfg, controllerDescriptors);
  72. }
  73. private static IHttpRoute RebuildRouteInternal(HttpRouteInformation routeInformation, HttpConfiguration cfg, Dictionary<Type, HttpControllerDescriptor> controllerDescriptors)
  74. {
  75. var route = new HttpRoute(routeInformation.RouteTemplate, new HttpRouteValueDictionary(routeInformation.Defaults), new HttpRouteValueDictionary(routeInformation.Constraints), new HttpRouteValueDictionary(routeInformation.DataTokens), null);
  76. object value;
  77. if (route.DataTokens.TryGetValue(InfoDataTokenKey, out value))
  78. {
  79. var descriptorInformations = (HttpActionDescriptorInformation[])value;
  80. var descriptors = new HttpActionDescriptor[descriptorInformations.Length];
  81. for (var index = 0; index < descriptorInformations.Length; index++)
  82. {
  83. var descriptorInformation = descriptorInformations[index];
  84. HttpControllerDescriptor controllerDescriptor;
  85. if (controllerDescriptors.TryGetValue(descriptorInformation.ControllerType, out controllerDescriptor) == false)
  86. controllerDescriptors[descriptorInformation.ControllerType] = controllerDescriptor = new HttpControllerDescriptor(cfg, descriptorInformation.ControllerName, descriptorInformation.ControllerType);
  87. var descriptor = new ReflectedHttpActionDescriptor(controllerDescriptor, descriptorInformation.MethodInfo);
  88. foreach (var pair in descriptorInformation.Properties)
  89. descriptor.Properties.AddOrUpdate(pair.Key, pair.Value, (_, __) => pair.Value);
  90. descriptors[index] = descriptor;
  91. }
  92. route.DataTokens.Remove(InfoDataTokenKey);
  93. route.DataTokens[ActionsDataTokenKey] = descriptors;
  94. }
  95. return route;
  96. }
  97. private static IEnumerable<HttpRouteInformation> CacheRoutes(IHttpRoute route)
  98. {
  99. var collection = route as IReadOnlyCollection<IHttpRoute>;
  100. if (collection != null)
  101. {
  102. var routes = collection
  103. .Select(CacheRouteInternal)
  104. .ToList();
  105. yield return new HttpRouteCollectionInformation(routes);
  106. yield break;
  107. }
  108. yield return CacheRouteInternal(route);
  109. }
  110. private static HttpRouteInformation CacheRouteInternal(IHttpRoute route)
  111. {
  112. var httpRoute = route as HttpRoute;
  113. if (httpRoute == null)
  114. throw new InvalidOperationException("Invalid route");
  115. if (httpRoute.Handler != null)
  116. throw new InvalidOperationException("Cannot copy route with handler: " + route.RouteTemplate);
  117. var routeInformation = new HttpRouteInformation
  118. {
  119. Constraints = httpRoute.Constraints.ToDictionary(x => x.Key, x => x.Value),
  120. DataTokens = httpRoute.DataTokens.ToDictionary(x => x.Key, x => x.Value),
  121. Defaults = httpRoute.Defaults.ToDictionary(x => x.Key, x => x.Value),
  122. RouteTemplate = httpRoute.RouteTemplate
  123. };
  124. object value;
  125. if (routeInformation.DataTokens.TryGetValue(ActionsDataTokenKey, out value))
  126. {
  127. var descriptors = (HttpActionDescriptor[])value;
  128. var descriptorInformations = new HttpActionDescriptorInformation[descriptors.Length];
  129. for (var index = 0; index < descriptors.Length; index++)
  130. {
  131. var descriptor = (ReflectedHttpActionDescriptor)descriptors[index];
  132. var methodInfo = descriptor.MethodInfo;
  133. var controllerName = descriptor.ControllerDescriptor.ControllerName;
  134. var controllerType = descriptor.ControllerDescriptor.ControllerType;
  135. var properties = descriptor.Properties.ToDictionary(x => x.Key, x => x.Value);
  136. descriptorInformations[index] = new HttpActionDescriptorInformation
  137. {
  138. MethodInfo = methodInfo,
  139. ControllerName = controllerName,
  140. ControllerType = controllerType,
  141. Properties = properties
  142. };
  143. }
  144. routeInformation.DataTokens.Remove(ActionsDataTokenKey);
  145. routeInformation.DataTokens[InfoDataTokenKey] = descriptorInformations;
  146. }
  147. return routeInformation;
  148. }
  149. private class HttpRouteCollectionInformation : HttpRouteInformation
  150. {
  151. public IReadOnlyCollection<HttpRouteInformation> Routes { get; private set; }
  152. public HttpRouteCollectionInformation(IReadOnlyCollection<HttpRouteInformation> routes)
  153. {
  154. Routes = routes;
  155. }
  156. }
  157. private class HttpRouteInformation
  158. {
  159. public string RouteTemplate { get; set; }
  160. public IDictionary<string, object> Defaults { get; set; }
  161. public IDictionary<string, object> Constraints { get; set; }
  162. public IDictionary<string, object> DataTokens { get; set; }
  163. }
  164. private class HttpActionDescriptorInformation
  165. {
  166. public string ControllerName { get; set; }
  167. public Type ControllerType { get; set; }
  168. public MethodInfo MethodInfo { get; set; }
  169. public Dictionary<object, object> Properties { get; set; }
  170. }
  171. }
  172. }