Beispiel #1
0
        public void Descriptions_RecognizesCompositeRoutes()
        {
            var config               = new HttpConfiguration();
            var routeTemplate        = "api/values";
            var controllerDescriptor = new HttpControllerDescriptor(
                config,
                "AttributeApiExplorerValues",
                typeof(AttributeApiExplorerValuesController)
                );
            var action = new ReflectedHttpActionDescriptor(
                controllerDescriptor,
                typeof(AttributeApiExplorerValuesController).GetMethod("Action")
                );
            var actions = new ReflectedHttpActionDescriptor[] { action };

            var routeCollection = new List <IHttpRoute>();

            routeCollection.Add(CreateDirectRoute(routeTemplate, actions));

            RouteCollectionRoute route = new RouteCollectionRoute();

            route.EnsureInitialized(() => routeCollection);

            config.Routes.Add("Route", route);

            var descriptions = new ApiExplorer(config).ApiDescriptions;

            ApiDescription description = Assert.Single(descriptions);

            Assert.Equal(HttpMethod.Get, description.HttpMethod);
            Assert.Equal(routeTemplate, description.RelativePath);
            Assert.Equal(action, description.ActionDescriptor);
        }
Beispiel #2
0
        /// <summary>
        /// Maps the attribute-defined routes for the application.
        /// </summary>
        /// <param name="routes"></param>
        /// <param name="controllerTypes">The controller types to scan.</param>
        /// <param name="constraintResolver">The <see cref="IInlineConstraintResolver"/> to use for resolving inline constraints in route templates.</param>
        internal static void MapMvcAttributeRoutes(this RouteCollection routes, IEnumerable <Type> controllerTypes, IInlineConstraintResolver constraintResolver)
        {
            List <RouteEntry> routeEntries = new AttributeRoutingMapper(new RouteBuilder2(constraintResolver)).MapMvcAttributeRoutes(controllerTypes);

            // This sort is here to enforce a static ordering for link generation using these routes.
            // We don't apply dynamic criteria like ActionSelectors on link generation, but we can use the static ones.
            RouteEntry[] sorted = routeEntries.OrderBy(r => r.Route.GetOrder()).ThenBy(r => r.Route.GetPrecedence()).ToArray();

            RouteCollectionRoute aggregateRoute = new RouteCollectionRoute();

            if (sorted.Length > 0)
            {
                routes.Add(aggregateRoute);
            }

            foreach (var routeEntry in sorted)
            {
                aggregateRoute.SubRoutes.Add(routeEntry.Name, routeEntry.Route);

                if (routeEntry.Name == null)
                {
                    routes.Add(new GenerationRoute(routeEntry.Route));
                }
                else
                {
                    routes.Add(routeEntry.Name, new GenerationRoute(routeEntry.Route));
                }
            }
        }
        /// <summary>
        /// Maps the attribute-defined routes for the application.
        /// </summary>
        /// <param name="configuration">The server configuration.</param>
        /// <param name="constraintResolver">The <see cref="IInlineConstraintResolver"/> to use for resolving inline constraints.</param>
        public static void MapHttpAttributeRoutes(this HttpConfiguration configuration, IInlineConstraintResolver constraintResolver)
        {
            HttpRouteBuilder routeBuilder = new HttpRouteBuilder(constraintResolver);
            var attrRoute = new RouteCollectionRoute();

            configuration.Routes.Add(AttributeRouteName, attrRoute);

            Action <HttpConfiguration> previousInitializer = configuration.Initializer;

            configuration.Initializer = config =>
            {
                // Chain to the previous initializer hook. Do this before we access the config since
                // initialization may make last minute changes to the configuration.
                previousInitializer(config);

                // Add a single placeholder route that handles all of attribute routing.
                // Add an initialize hook that initializes these routes after the config has been initialized.
                Func <HttpSubRouteCollection> initializer = () => MapHttpAttributeRoutesInternal(configuration, routeBuilder);

                // This won't change config. It wants to pick up the finalized config.
                HttpSubRouteCollection subRoutes = attrRoute.EnsureInitialized(initializer);
                if (subRoutes != null)
                {
                    AddGenerationHooksForSubRoutes(config.Routes, subRoutes, routeBuilder);
                }
            };
        }
Beispiel #4
0
        public static RouteCollectionRoute BuildDirectRouteFromMethod <T>(Expression <Action <T> > methodCall)
        {
            var route = new RouteCollectionRoute();

            AddDirectRouteFromMethod(route, methodCall);
            return(route);
        }
        /// <summary>
        /// Maps the attribute-defined routes for the application.
        /// </summary>
        /// <param name="routes"></param>
        /// <param name="controllerTypes">The controller types to scan.</param>
        /// <param name="constraintResolver">
        /// The <see cref="IInlineConstraintResolver"/> to use for resolving inline constraints in route templates.
        /// </param>
        public static void MapAttributeRoutes(RouteCollection routes, IEnumerable<Type> controllerTypes,
            IInlineConstraintResolver constraintResolver)
        {
            SubRouteCollection subRoutes = new SubRouteCollection();
            AddRouteEntries(subRoutes, controllerTypes, constraintResolver);
            IReadOnlyCollection<RouteEntry> entries = subRoutes.Entries;

            if (entries.Count > 0)
            {
                RouteCollectionRoute aggregrateRoute = new RouteCollectionRoute(subRoutes);
                routes.Add(aggregrateRoute);

                // This sort is here to enforce a static ordering for link generation using these routes. 
                // We don't apply dynamic criteria like ActionSelectors on link generation, but we can use the static
                // ones.
                //
                // Routes to actions are placed first because they are considered more specific. A route to an action
                // will only match for link generation if the action name was supplied, so this is essential for
                // correctness. Without this a controller-level route could be 'greedy' and generate a link when
                // the action-level route was intended.
                RouteEntry[] sorted = entries
                    .OrderBy(r => r.Route.GetOrder())
                    .ThenBy(r => r.Route.GetTargetIsAction() ? 0 : 1)
                    .ThenBy(r => r.Route.GetPrecedence())
                    .ToArray();

                AddGenerationHooksForSubRoutes(routes, sorted);
            }
        }
Beispiel #6
0
        public static RouteCollectionRoute BuildDirectRouteFromController <T>()
        {
            RouteCollectionRoute route = new RouteCollectionRoute();

            AddDirectRouteFromController <T>(route);
            return(route);
        }
Beispiel #7
0
        public static void AddDirectRouteMatches(
            this RouteData routeData,
            Func <RouteBase, RouteData, bool> selector = null
            )
        {
            RouteCollectionRoute route = (RouteCollectionRoute)routeData.Route;

            List <RouteData> matches = new List <RouteData>();

            foreach (var subRoute in route)
            {
                RouteData match = new RouteData()
                {
                    Route = subRoute
                };
                bool isMatch = selector == null ? true : selector(subRoute, match);
                if (isMatch)
                {
                    matches.Add(match);
                }
            }

            if (matches.Any())
            {
                routeData.SetDirectRouteMatches(matches);
            }
        }
        /// <summary>
        /// Maps the attribute-defined routes for the application.
        /// </summary>
        /// <param name="configuration">The server configuration.</param>
        /// <param name="constraintResolver">The <see cref="IInlineConstraintResolver"/> to use for resolving inline constraints.</param>
        public static void MapHttpAttributeRoutes(this HttpConfiguration configuration, IInlineConstraintResolver constraintResolver)
        {
            HttpRouteBuilder routeBuilder = new HttpRouteBuilder(constraintResolver);
            var attrRoute = new RouteCollectionRoute();
            configuration.Routes.Add(AttributeRouteName, attrRoute);

            Action<HttpConfiguration> previousInitializer = configuration.Initializer;
            configuration.Initializer = config =>
                {
                    // Chain to the previous initializer hook. Do this before we access the config since
                    // initialization may make last minute changes to the configuration.
                    previousInitializer(config);

                    // Add a single placeholder route that handles all of attribute routing.
                    // Add an initialize hook that initializes these routes after the config has been initialized.
                    Func<HttpSubRouteCollection> initializer = () => MapHttpAttributeRoutesInternal(configuration, routeBuilder);

                    // This won't change config. It wants to pick up the finalized config.
                    HttpSubRouteCollection subRoutes = attrRoute.EnsureInitialized(initializer);
                    if (subRoutes != null)
                    {
                        AddGenerationHooksForSubRoutes(config.Routes, subRoutes, routeBuilder);
                    }
                };
        }
Beispiel #9
0
        private static RouteData CreateRouteData(RouteBase route, RouteValueDictionary routeValues, RouteValueDictionary dataTokens, ViewContext parentViewContext)
        {
            RouteData routeData = new RouteData();

            foreach (KeyValuePair <string, object> kvp in routeValues)
            {
                routeData.Values.Add(kvp.Key, kvp.Value);
            }

            foreach (KeyValuePair <string, object> kvp in dataTokens)
            {
                routeData.DataTokens.Add(kvp.Key, kvp.Value);
            }

            routeData.Route = route;
            routeData.DataTokens[ControllerContext.ParentActionViewContextToken] = parentViewContext;

            // It's possible that the outgoing route is a direct route - in which case it's not possible to reach using
            // the action name and controller name. We need to check for that case to determine if we need to create a
            // 'direct route' routedata to reach it.
            if (route.IsDirectRoute())
            {
                return(RouteCollectionRoute.CreateDirectRouteMatch(route, new List <RouteData>()
                {
                    routeData
                }));
            }
            else
            {
                return(routeData);
            }
        }
        private ICollection <Route> GetAttributeRoutes(RouteCollection routes)
        {
            RouteCollectionRoute attributeRoute = routes.OfType <RouteCollectionRoute>().Single();

            Assert.NotNull(attributeRoute);

            return(attributeRoute.SubRoutes);
        }
        private static RouteData CreateRouteData(
            RouteBase route,
            RouteValueDictionary routeValues,
            RouteValueDictionary dataTokens,
            ViewContext parentViewContext
            )
        {
            RouteData routeData = new RouteData();

            foreach (KeyValuePair <string, object> kvp in routeValues)
            {
                routeData.Values.Add(kvp.Key, kvp.Value);
            }

            foreach (KeyValuePair <string, object> kvp in dataTokens)
            {
                routeData.DataTokens.Add(kvp.Key, kvp.Value);
            }

            routeData.Route = route;
            routeData.DataTokens[ControllerContext.ParentActionViewContextToken] =
                parentViewContext;

            // It's possible that the outgoing route is a direct route - in which case it's not possible to reach using
            // the action name and controller name. We need to check for that case to determine if we need to create a
            // 'direct route' routedata to reach it.
            if (route.IsDirectRoute())
            {
                // Codeplex-2136 - ControllerContext.IsChildAction returns false inside Controller.Initialize()
                //
                // We're constructing a 'temp' route data to wrap the route data for the match we're invoking via
                // an attribute route. The ControllerContext will look at datatokens to see if it's being invoked
                // as a child action.
                //
                // By sticking the view context on both route data ControllerContext will do the right thing
                // at all parts of the pipeline.
                var directRouteData = RouteCollectionRoute.CreateDirectRouteMatch(
                    route,
                    new List <RouteData>()
                {
                    routeData
                }
                    );
                directRouteData.DataTokens[ControllerContext.ParentActionViewContextToken] =
                    parentViewContext;
                return(directRouteData);
            }
            else
            {
                return(routeData);
            }
        }
        public static void MapAttributeRoutes(
            HttpConfiguration configuration,
            IInlineConstraintResolver constraintResolver,
            IDirectRouteProvider directRouteProvider)
        {
            if (configuration == null)
            {
                throw new ArgumentNullException("configuration");
            }

            if (constraintResolver == null)
            {
                throw new ArgumentNullException("constraintResolver");
            }

            if (directRouteProvider == null)
            {
                throw new ArgumentNullException("directRouteProvider");
            }

            RouteCollectionRoute aggregateRoute = new RouteCollectionRoute();
            configuration.Routes.Add(AttributeRouteName, aggregateRoute);

            Action<HttpConfiguration> previousInitializer = configuration.Initializer;
            configuration.Initializer = config =>
                {
                    // Chain to the previous initializer hook. Do this before we access the config since
                    // initialization may make last minute changes to the configuration.
                    previousInitializer(config);

                    SubRouteCollection subRoutes = null;

                    // Add a single placeholder route that handles all of attribute routing.
                    // Add an initialize hook that initializes these routes after the config has been initialized.
                    Func<SubRouteCollection> initializer = () =>
                    {
                        subRoutes = new SubRouteCollection();
                        AddRouteEntries(subRoutes, configuration, constraintResolver, directRouteProvider);
                        return subRoutes;
                    };

                    // This won't change config. It wants to pick up the finalized config.
                    aggregateRoute.EnsureInitialized(initializer);

                    if (subRoutes != null)
                    {
                        AddGenerationHooksForSubRoutes(config.Routes, subRoutes.Entries);
                    }
                };
        }
Beispiel #13
0
        public static void AddDirectRouteFromController <T>(this RouteBase routeBase)
        {
            RouteCollectionRoute route = (RouteCollectionRoute)routeBase;

            var controllerType = typeof(T);
            var entries        = new AttributeRoutingMapper(new RouteBuilder2()).MapMvcAttributeRoutes(new Type[]
            {
                controllerType,
            });

            foreach (var entry in entries)
            {
                route.SubRoutes.Add(entry.Route);
            }
        }
Beispiel #14
0
        public static void AddDirectRouteFromMethod <T>(this RouteBase routeBase, Expression <Action <T> > methodCall)
        {
            RouteCollectionRoute route = (RouteCollectionRoute)routeBase;

            var method     = ((MethodCallExpression)methodCall.Body).Method;
            var attributes = method.GetCustomAttributes(false).OfType <IRouteInfoProvider>();

            var controllerDescriptor = new ReflectedAsyncControllerDescriptor(method.DeclaringType);
            var actionDescriptor     = new ReflectedActionDescriptor(method, method.Name, controllerDescriptor);

            foreach (var attribute in attributes)
            {
                var subRoute = new Route(attribute.Template, routeHandler: null);
                subRoute.SetTargetActionDescriptors(new ActionDescriptor[] { actionDescriptor });
                subRoute.SetTargetControllerDescriptor(controllerDescriptor);
                route.SubRoutes.Add(subRoute);
            }
        }
        public void Descriptions_RecognizesCompositeRoutes()
        {
            var config = new HttpConfiguration();
            var routeTemplate = "api/values";
            var controllerDescriptor = new HttpControllerDescriptor(config, "AttributeApiExplorerValues", typeof(AttributeApiExplorerValuesController));
            var action = new ReflectedHttpActionDescriptor(controllerDescriptor, typeof(AttributeApiExplorerValuesController).GetMethod("Action"));
            var actions = new ReflectedHttpActionDescriptor[] { action };

            var routeCollection = new HttpSubRouteCollection();
            routeCollection.Add("testroute", new HttpDirectRoute(routeTemplate, 0, actions));

            RouteCollectionRoute route = new RouteCollectionRoute();
            route.EnsureInitialized(() => routeCollection);

            config.Routes.Add("Route", route);

            var descriptions = new ApiExplorer(config).ApiDescriptions;

            ApiDescription description = Assert.Single(descriptions);
            Assert.Equal(HttpMethod.Get, description.HttpMethod);
            Assert.Equal(routeTemplate, description.RelativePath);
            Assert.Equal(action, description.ActionDescriptor);
        }