static KeyValuePair <string, IHttpRoute>[] CopyRouteEntries(HttpRouteCollection routes) { Contract.Requires(routes != null); Contract.Ensures(Contract.Result <KeyValuePair <string, IHttpRoute>[]>() != null); var items = new KeyValuePair <string, IHttpRoute> [routes.Count]; try { routes.CopyTo(items, 0); } catch (NotSupportedException) when(routes.GetType().FullName == "System.Web.Http.WebHost.Routing.HostedHttpRouteCollection") { var keys = GetRouteKeys(routes); for (var i = 0; i < keys.Count; i++) { var key = keys[i]; var route = routes[key]; items[i] = new KeyValuePair <string, IHttpRoute>(key, route); } } return(items); }
static ICollection <string> GetDictionaryKeys(HttpRouteCollection routes) { // HACK: System.Web.Routing.RouteCollection doesn't expose the names associated with registered routes. The // HostedHttpRouteCollection could have provided an adapter to support it, but didn't. Instead, it always throws // NotSupportedException for the HttpRouteCollection.CopyTo method. This only happens when hosted on IIS. The // only way to get the keys is use reflection to poke at the underlying dictionary. var routeCollection = routes.GetType().GetField("_routeCollection", Instance | NonPublic).GetValue(routes); var dictionary = routeCollection.GetType().GetField("_namedMap", Instance | NonPublic).GetValue(routeCollection); var keys = (ICollection <string>)dictionary.GetType().GetRuntimeProperty("Keys").GetValue(dictionary, null); return(keys); }
/// <summary> /// Returns the route collection as a read-only dictionary mapping configured names to routes. /// </summary> /// <param name="routes">The <see cref="HttpRouteCollection">route collection</see> to convert.</param> /// <returns>A new <see cref="IReadOnlyDictionary{TKey, TValue}">read-only dictonary</see> of /// <see cref="IHttpRoute">routes</see> mapped to their name.</returns> public static IReadOnlyDictionary <string, IHttpRoute> ToDictionary(this HttpRouteCollection routes) { Arg.NotNull(routes, nameof(routes)); Contract.Ensures(Contract.Result <IReadOnlyDictionary <string, IHttpRoute> >() != null); const string HostedHttpRouteCollection = "System.Web.Http.WebHost.Routing.HostedHttpRouteCollection"; try { return(routes.CopyToDictionary()); } catch (NotSupportedException) when(routes.GetType().FullName == HostedHttpRouteCollection) { return(routes.BuildDictionaryFromKeys()); } }
/// <summary> /// Returns the route collection as a read-only dictionary mapping configured names to routes. /// </summary> /// <param name="routes">The <see cref="HttpRouteCollection">route collection</see> to convert.</param> /// <returns>A new <see cref="IReadOnlyDictionary{TKey, TValue}">read-only dictonary</see> of /// <see cref="IHttpRoute">routes</see> mapped to their name.</returns> public static IReadOnlyDictionary <string, IHttpRoute> ToDictionary(this HttpRouteCollection routes) { if (routes == null) { throw new ArgumentNullException(nameof(routes)); } const string HostedHttpRouteCollection = "System.Web.Http.WebHost.Routing.HostedHttpRouteCollection"; try { return(routes.CopyToDictionary()); } catch (NotSupportedException) when(routes.GetType().FullName == HostedHttpRouteCollection) { return(routes.BuildDictionaryFromKeys()); } }