/// <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 RoutePath table from the controller type, action method reflection info and full path. /// </summary> private List <RoutePath> GetRoutePath(MethodInfo action, string fullpath) { List <RoutePath> result = new List <RoutePath>(); if (string.IsNullOrEmpty(fullpath)) { result.Add(new RoutePath { Type = RouteType.Text, Value = "" }); return(result); } //split path to parts. //each part will be replaced to RoutePath class with extra information string[] parts = fullpath.ToLower(new CultureInfo("en-US")).Split('/', StringSplitOptions.RemoveEmptyEntries); foreach (string part in parts) { if (string.IsNullOrEmpty(part)) { continue; } RoutePath route = new RoutePath(); if (part == "[action]") { route.Type = RouteType.Text; route.Value = action.Name.ToLower(new CultureInfo("en-US")); } //if the part is parameter check if it's optional or not and set value as parameter name else if (part.StartsWith('{')) { route.Type = part.Substring(1, 1) == "?" ? RouteType.OptionalParameter : RouteType.Parameter; route.Value = route.Type == RouteType.OptionalParameter ? part.Substring(2, part.Length - 3) : part.Substring(1, part.Length - 2); } //for all other kinds set the value directly as text type. else { route.Type = RouteType.Text; route.Value = part; } result.Add(route); } return(result); }
/// <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) { bool isAsync = (AsyncStateMachineAttribute)method.GetCustomAttribute(typeof(AsyncStateMachineAttribute)) != null; if (!isAsync && method.ReturnType.IsGenericType) { if (typeof(Task).IsAssignableFrom(method.ReturnType.GetGenericTypeDefinition())) { isAsync = true; } } leaf.Route = new Route { ActionType = method, ControllerType = controllerType, Method = info.Method, Path = path.ToArray(), Parameters = BuildParameters(method), IsAsyncMethod = isAsync }; } } ApplyControllerAttributes(leaf.Route, controllerType); ApplyActionAttributes(leaf.Route, method); } } } return(routes); }