/// <summary> /// Get the possible route datas that could have selected a given container or content item via a route /// </summary> /// <param name="route">The route</param> /// <param name="o">The container or content item</param> /// <returns>The route datas that could have accessed the object via the route</returns> public List<RouteData> GetRouteDatas(Route route, Address address) { // Start list of urls which could map to this item. Note, catchall items (starting *) are treated as normal ones List<RouteValueDictionary> rvds = new List<RouteValueDictionary>(); var keyOutputs = route.KeyOutputs(); Type type = address.Type; ICollator collator = Collator.Instance.Registered(type); var rvd = new RouteValueDictionary(address); // Action & controller if (!(keyOutputs.ContainsKey("controller") && keyOutputs.ContainsKey("action"))) throw new Exception("Route " + route.Url + " fails to define controller and action"); if (keyOutputs["controller"].StartsWith("?")) throw new Exception("Route " + route.Url + " is a data route which lacks but must have a specified controller"); if (!ContentTypeHierarchy.ControllerActions.ContainsKey(keyOutputs["controller"])) return new List<RouteData>(); // Controller doesn't exist therefore no rvds rvd.Add("controller", keyOutputs["controller"]); rvds.Add(rvd); // copy list so we can change 'actions' var actions = ContentTypeHierarchy.ControllerActions[keyOutputs["controller"]].ToList(); if (keyOutputs["action"].StartsWith("?")) { if (keyOutputs["action"].Length > 1 && actions.Contains(keyOutputs["action"].Substring(1).ToLower())) actions.Add("??"); rvds = PermuteAdd(rvds, "action", actions); } else if (!actions.Contains(keyOutputs["action"])) return new List<RouteData>(); // Fixed action doesn't exist therefore no urls else rvd.Add("action", keyOutputs["action"]); // Route vars addressing the content item foreach (var kvp in keyOutputs) { if (kvp.Key == "controller" || kvp.Key == "action") // already dealt with continue; if (kvp.Value == "??" && address.ContainsKey(kvp.Key)) // optional variable { address.SetMatched(kvp.Key); } else if (kvp.Value.StartsWith("?")) // variable takes any value { // matches a path element address.SetMatched(kvp.Key); // this address element is matched } else // fixed value, has to be matched by item { bool matched = false; if (address.ContainsKey(kvp.Key)) { if (address.GetAsString(kvp.Key) == kvp.Value) { matched = true; address.SetMatched(kvp.Key); } } if (!matched) return new List<RouteData>(); } } if (!address.FullyMatched) // Fails because one or more address elements could not have come from this route return new List<RouteData>(); return rvds .Select(r => { var rd = new RouteData(); r.Do(kvp => rd.Values.Add(kvp.Key, kvp.Value)); rd.Route = route; rd.RouteHandler = route.RouteHandler; return rd; }) .ToList(); }
/// <summary> /// Get the possible urls that could have selected a given container or content item via a given route /// </summary> /// <param name="route">The route</param> /// <param name="address">The content address</param> /// <returns>The urls that could have accessed the object via the route</returns> public List<string> GetUrls(Route route, Address address) { // Start list of urls which could map to this item. Note, catchall items (starting *) are treated as normal ones List<string> urls = new List<string> { route.Url.Replace("{*", "{") }; var keyOutputs = route.KeyOutputs(); List<string> replaceWiths = null; // Action & controller if (!(keyOutputs.ContainsKey("controller") && keyOutputs.ContainsKey("action"))) throw new Exception("Route " + route.Url + " fails to define controller and action"); if (keyOutputs["controller"].StartsWith("?")) throw new Exception("Route " + route.Url + " is a data route which lacks but must have a specified controller"); if (!ContentTypeHierarchy.ControllerActions.ContainsKey(keyOutputs["controller"])) return new List<string>(); // Controller doesn't exist therefore no urls // copy list so we can change 'actions' var actions = ContentTypeHierarchy.ControllerActions[keyOutputs["controller"]].ToList(); if (keyOutputs["action"].StartsWith("?")) { if (keyOutputs["action"].Length > 1 && actions.Contains(keyOutputs["action"].Substring(1).ToLower())) actions.Add("??"); UrlX.PermuteReplace(urls, "{action}", actions); } else if (!actions.Contains(keyOutputs["action"])) return new List<string>(); // Fixed action doesn't exist therefore no urls // Route vars addressing the content item foreach (var kvp in keyOutputs) { if (kvp.Key == "controller" || kvp.Key == "action") // already dealt with continue; if (kvp.Value.StartsWith("?") && kvp.Value != "??") // variable takes any value { if (address.ContainsKey(kvp.Key)) // its part of the content item address { // path element is the default value, so this url element is optional replaceWiths = new List<string> { address.GetAsString(kvp.Key) }; if (kvp.Value.Length > 1 && address.GetAsString(kvp.Key) == kvp.Value.Substring(1)) replaceWiths.Add("??"); // matches a path element address.SetMatched(kvp.Key); // this address element is matched } else { replaceWiths = new List<string> { "?" };// no match, so many urls mapped to this item int nUrls = urls.Count; if (kvp.Value.Length > 1) // there's a default value so the element is optional replaceWiths.Add("??"); } UrlX.PermuteReplace(urls, "{" + kvp.Key + "}", replaceWiths); } else if (kvp.Value == "??") { UrlX.PermuteReplace(urls, "{" + kvp.Key + "}", new List<string> { "??" }); // optional variable } else // fixed value, has to be matched by item { bool matched = false; if (address.ContainsKey(kvp.Key)) { if (address.GetAsString(kvp.Key) == kvp.Value) { matched = true; address.SetMatched(kvp.Key); } } if (!matched) return new List<string>(); } } if (!address.FullyMatched) // Fails because one or more address elements could not have come from this route return new List<string>(); // Deal with possible url variations with omitted path elements for (int i = 0; i < urls.Count; i++) { while (urls[i].EndsWith("/??")) urls[i] = urls[i].Substring(0, urls[i].Length - 3); if (urls[i].Contains("??")) urls[i] = null; } return urls.Where(u => u != null).OrderBy(u => u.Split('/').Length).Select(u => "/" + u).ToList(); }
public List<string> GetUrls(Route route, object item) { string url = route.Url; var keyOutputs = route.KeyOutputs(); foreach (var kvp in keyOutputs) { if (kvp.Key == "@id") // We're looking at the id variable, the only one matchable by our item { PropertyInfo keyProp = item.GetType().GetProperties().FirstOrDefault(p => p.CustomAttributes.Any(cad => cad.AttributeType == typeof(KeyAttribute))); if (keyProp != null) { string id = keyProp.GetValue(item).ToString(); url.Replace("{@id}", id); } else url.Replace("{@id}", "?"); } else if (kvp.Value == "?" || kvp.Value == "??") url.Replace("{" + kvp.Key + "}", kvp.Value); else if (kvp.Value.StartsWith("?")) { url.Replace("{" + kvp.Key + "}", "?"); } } while (url.EndsWith("/??")) url = url.UpToLast("/??"); return new List<string> { url }; }