/// <summary> /// Finds matched route from the list with specified request /// </summary> public RouteMatch Find(IEnumerable <RouteLeaf> routes, HttpRequest request) { //split path to route parts string[] parts = request.Path.Split('/', StringSplitOptions.RemoveEmptyEntries); if (parts.Length == 0) { parts = new[] { "" } } ; RouteLeaf route = null; foreach (RouteLeaf leaf in routes) { RouteLeaf found = FindRouteInLeaf(leaf, request.Method, parts, 0); if (found != null) { route = found; break; } } if (route == null) { return(null); } RouteMatch match = new RouteMatch(); match.Values = new Dictionary <string, object>(StringComparer.InvariantCultureIgnoreCase); match.Route = route.Route; do { RoutePath path = route.Path; //if type is optional parameter we dont need to check if equals //we just need to read the part value and put it into value list (if doesn't exists put default value) if (path.Type == RouteType.OptionalParameter) { match.Values.Add(path.Value, parts.Length <= route.Index ? null : parts[route.Index]); } //if type is parameter we dont need to check if equals //we just need to read the part value and put it into value list else if (path.Type == RouteType.Parameter) { match.Values.Add(path.Value, parts[route.Index]); } route = route.Parent; } while (route != null); return(match); } }
/// <summary> /// Creates all Route objects of the specified Controller type /// </summary> public IEnumerable <RouteLeaf> BuildRoutes(Type controllerType) { //find base path for the controller List <RouteLeaf> routes = CreateControllerRoutes(controllerType); List <RouteLeaf> edges = new List <RouteLeaf>(); foreach (RouteLeaf leaf in routes) { edges.AddRange(GetEdgeLeaves(leaf)); } MethodInfo[] methods = controllerType.GetMethods(); foreach (MethodInfo method in methods) { //find method route if exists List <RouteInfo> methodRoutes = FindActionRoute(method); if (methodRoutes.Count == 0) { continue; } foreach (RouteLeaf cleaf in edges) { foreach (RouteInfo info in methodRoutes) { //get route table from the fullpath List <RoutePath> path = GetRoutePath(method, info.Pattern); RouteLeaf leaf = cleaf; for (int i = 0; i < path.Count; i++) { RoutePath rp = path[i]; RouteLeaf child = new RouteLeaf(rp, leaf); leaf.Children.Add(child); leaf = child; if (i == path.Count - 1) { leaf.Route = new Route { ActionType = method, ControllerType = controllerType, Method = info.Method, Path = path.ToArray(), Parameters = BuildParameters(method), IsAsyncMethod = (AsyncStateMachineAttribute)method.GetCustomAttribute(typeof(AsyncStateMachineAttribute)) != null }; } } ApplyControllerAttributes(leaf.Route, controllerType); ApplyActionAttributes(leaf.Route, method); } } } return(routes); }
/// <summary> /// Creates new leaf in specified path /// </summary> public RouteLeaf(RoutePath path, RouteLeaf parent) { Children = new List <RouteLeaf>(); Path = path; Parent = parent; if (parent != null && !string.IsNullOrEmpty(parent.Path.Value)) { Index = parent.Index + 1; } }
/// <summary> /// Finds route value for the controller type /// </summary> private static List <RouteLeaf> CreateControllerRoutes(Type controllerType) { List <RouteLeaf> routes = new List <RouteLeaf>(); IEnumerable <RouteAttribute> attributes = controllerType.GetCustomAttributes <RouteAttribute>(true); foreach (RouteAttribute attr in attributes) { string value = attr.Pattern; if (value == null) { routes.Add(new RouteLeaf(new RoutePath(RouteType.Text, FindControllerRouteName(controllerType)), null)); continue; } if (value == "") { routes.Add(new RouteLeaf(new RoutePath(RouteType.Text, ""), null)); continue; } string[] pathLeaves = value.Split('/', StringSplitOptions.RemoveEmptyEntries); RouteLeaf parent = null; foreach (string p in pathLeaves) { string v = p; if (p.Equals("[controller]", StringComparison.InvariantCultureIgnoreCase)) { v = FindControllerRouteName(controllerType); } RouteLeaf leaf = new RouteLeaf(new RoutePath(RouteType.Text, v), parent); if (parent == null) { routes.Add(leaf); } else { parent.Children.Add(leaf); } parent = leaf; } } //if there is no route definition, the route value is the name of the controller if (routes.Count == 0) { routes.Add(new RouteLeaf(new RoutePath(RouteType.Text, FindControllerRouteName(controllerType)), null)); } return(routes); }
/// <summary> /// Sorts all route leaves recursively /// </summary> internal void SortChildren(RouteLeaf leaf) { if (leaf.Children.Count == 0) { return; } SortRoutes(leaf.Children); foreach (RouteLeaf child in leaf.Children) { SortChildren(child); } }
private IEnumerable <RouteLeaf> GetEdgeLeaves(RouteLeaf root) { if (root.Children.Count == 0) { yield return(root); yield break; } foreach (RouteLeaf leaf in root.Children) { IEnumerable <RouteLeaf> leaves = GetEdgeLeaves(leaf); foreach (RouteLeaf child in leaves) { yield return(child); } } }
private RouteLeaf FindRouteInLeaf(RouteLeaf leaf, string method, string[] parts, int index) { //for text parts, it should match if (leaf.Path.Type == RouteType.Text) { bool matched = leaf.Path.Value.Equals(parts[index], StringComparison.InvariantCultureIgnoreCase); if (!matched) { return(null); } } //if leaf is last of path check method and return if equals if (leaf.Route != null) { if (parts.Length == index + 1 && leaf.Route.Method.Equals(method, StringComparison.InvariantCultureIgnoreCase)) { return(leaf); } return(null); } if (leaf.Children.Count == 0) { return(null); } //parts are done but route may keep going to optional parameters if (parts.Length == index + 1) { RouteLeaf x = leaf; while (x.Children.Count == 1) { RouteLeaf y = x.Children[0]; if (y.Path.Type == RouteType.Text && string.IsNullOrEmpty(y.Path.Value)) { if (y.Route.Method.Equals(method, StringComparison.InvariantCultureIgnoreCase)) { return(y); } return(null); } if (y.Path.Type != RouteType.OptionalParameter) { break; } if (y.Route != null) { if (y.Route.Method.Equals(method, StringComparison.InvariantCultureIgnoreCase)) { return(y); } break; } x = y; } } if (parts.Length < index + 2) { return(null); } int next = index + 1; foreach (RouteLeaf child in leaf.Children) { RouteLeaf found = FindRouteInLeaf(child, method, parts, next); if (found != null) { return(found); } } return(null); }