Beispiel #1
0
        protected void ValidateRouteArea(LocalizationCollectionRoute localizationCollectionRoute)
        {
            TActionDescriptor actionDescriptor =
                ((TActionDescriptor[])localizationCollectionRoute.DataTokens[RouteDataTokenKeys.Actions]).First();
            Type controllerType = actionDescriptor.ControllerDescriptor.ControllerType;

            RouteAreaAttribute routeAreaAttribute =
                controllerType.GetCustomAttributes(true).OfType <RouteAreaAttribute>().SingleOrDefault();

            if (routeAreaAttribute == null)
            {
                if (!string.IsNullOrEmpty(AreaPrefix) && Configuration.ValidateRouteArea)
                {
                    throw new InvalidOperationException(
                              string.Format(
                                  "AreaPrefix is set but Controller '{0}' does not contain any RouteArea attributes." +
                                  "Set Configuration.ValidateRouteArea to false, if you want to skip validation.", controllerType.FullName));
                }
            }
            else if (string.IsNullOrEmpty(AreaPrefix) && Configuration.UseUntranslatedAttributePrefixes)
            {
                // Use untranslated area name / prefix from attribute
                AreaPrefix = routeAreaAttribute.AreaPrefix ?? routeAreaAttribute.AreaName;
            }
        }
Beispiel #2
0
        /// <summary>
        /// Builds an <see cref="Route"/> for a particular controller.
        /// </summary>
        /// <param name="routeTemplate">The tokenized route template for the route.</param>
        /// <param name="controllerDescriptor">The controller the route attribute has been applied on.</param>
        /// <returns>The generated <see cref="Route"/>.</returns>
        public Route BuildDirectRoute(
            string routeTemplate,
            ControllerDescriptor controllerDescriptor
            )
        {
            if (routeTemplate == null)
            {
                throw Error.ArgumentNull("routeTemplate");
            }

            if (controllerDescriptor == null)
            {
                throw Error.ArgumentNull("controllerDescriptor");
            }

            string controllerName = controllerDescriptor.ControllerName;

            RouteAreaAttribute area     = controllerDescriptor.GetAreaFrom();
            string             areaName = controllerDescriptor.GetAreaName(area);

            RouteValueDictionary defaults = new RouteValueDictionary
            {
                { "controller", controllerName }
            };

            Type controllerType = controllerDescriptor.ControllerType;

            RouteValueDictionary dataTokens = new RouteValueDictionary();

            if (areaName != null)
            {
                dataTokens.Add(RouteDataTokenKeys.Area, areaName);
                dataTokens.Add(RouteDataTokenKeys.UseNamespaceFallback, value: false);
                if (controllerType != null)
                {
                    dataTokens.Add(
                        RouteDataTokenKeys.Namespaces,
                        new[] { controllerType.Namespace }
                        );
                }
            }

            RouteValueDictionary constraints = new RouteValueDictionary();
            string detokenizedRouteTemplate  = InlineRouteTemplateParser.ParseRouteTemplate(
                routeTemplate,
                defaults,
                constraints,
                ConstraintResolver
                );

            Route route = new Route(detokenizedRouteTemplate, new MvcRouteHandler())
            {
                Defaults    = defaults,
                Constraints = constraints,
                DataTokens  = dataTokens
            };

            return(route);
        }
Beispiel #3
0
        private static RouteAreaAttribute GetAreaFrom(ReflectedAsyncControllerDescriptor controllerDescriptor)
        {
            RouteAreaAttribute areaAttribute =
                controllerDescriptor.GetCustomAttributes(typeof(RouteAreaAttribute), true)
                .Cast <RouteAreaAttribute>()
                .FirstOrDefault();

            return(areaAttribute);
        }
        internal List <RouteEntry> MapMvcAttributeRoutes(ReflectedAsyncControllerDescriptor controllerDescriptor)
        {
            RoutePrefixAttribute prefixAttribute = GetPrefixFrom(controllerDescriptor);

            ValidatePrefixTemplate(prefixAttribute, controllerDescriptor);

            RouteAreaAttribute area       = GetAreaFrom(controllerDescriptor);
            string             areaName   = GetAreaName(controllerDescriptor, area);
            string             areaPrefix = area != null ? area.AreaPrefix ?? area.AreaName : null;

            ValidateAreaPrefixTemplate(areaPrefix, areaName, controllerDescriptor);

            string controllerName = controllerDescriptor.ControllerName;

            AsyncActionMethodSelector actionSelector    = controllerDescriptor.Selector;
            IEnumerable <MethodInfo>  actionMethodsInfo = actionSelector.AliasedMethods
                                                          .Concat(actionSelector.NonAliasedMethods.SelectMany(x => x))
                                                          .Where(m => m.DeclaringType == controllerDescriptor.ControllerType);

            if (actionSelector.AllowLegacyAsyncActions)
            {
                // if the ActionAsync / ActionCompleted pattern is used, we need to remove the "Completed" methods
                // and not look up routing attributes on them
                actionMethodsInfo =
                    actionMethodsInfo.Where(m => !m.Name.EndsWith("Completed", StringComparison.OrdinalIgnoreCase));
            }

            List <RouteEntry> routeEntries = new List <RouteEntry>();

            foreach (var method in actionMethodsInfo)
            {
                string actionName = GetCanonicalActionName(method, actionSelector.AllowLegacyAsyncActions);
                IEnumerable <IDirectRouteInfoProvider> routeAttributes = GetRouteAttributes(method);

                foreach (var routeAttribute in routeAttributes)
                {
                    ValidateTemplate(routeAttribute, actionName, controllerDescriptor);

                    string prefix = prefixAttribute != null ? prefixAttribute.Prefix : null;

                    string template = CombinePrefixAndAreaWithTemplate(areaPrefix, prefix, routeAttribute.RouteTemplate);
                    Route  route    = _routeBuilder.BuildDirectRoute(template, routeAttribute.Verbs, controllerName,
                                                                     actionName, method, areaName);
                    RouteEntry entry = new RouteEntry
                    {
                        Name          = routeAttribute.RouteName ?? template,
                        Route         = route,
                        RouteTemplate = template,
                        ParsedRoute   = RouteParser.Parse(route.Url),
                        Order         = routeAttribute.RouteOrder
                    };
                    routeEntries.Add(entry);
                }
            }

            return(routeEntries);
        }
        /// <summary>
        /// Gets the area name.
        /// </summary>
        /// <param name="routeAreaAttribute">The <see cref="RouteAreaAttribute"/> for the controller.</param>
        /// <param name="controllerType">The type of the controller.</param>
        /// <returns>The name of the area.</returns>
        private static string GetAreaName(RouteAreaAttribute routeAreaAttribute, Type controllerType)
        {
            if (routeAreaAttribute == null)
                return null;

            // If given an area name, then use it.
            // Otherwise, use the last section of the namespace of the controller, as a convention.
            return routeAreaAttribute.AreaName ?? controllerType.GetConventionalAreaName();
        }
        /// <summary>
        /// Gets the area prefix from the provided controller.
        /// </summary>
        /// <param name="controllerDescriptor">The controller descriptor.</param>
        /// <returns>The area prefix or null.</returns>
        protected virtual string GetAreaPrefix(ControllerDescriptor controllerDescriptor)
        {
            RouteAreaAttribute area       = controllerDescriptor.GetAreaFrom();
            string             areaName   = controllerDescriptor.GetAreaName(area);
            string             areaPrefix = area != null ? area.AreaPrefix ?? area.AreaName : null;

            ValidateAreaPrefixTemplate(areaPrefix, areaName, controllerDescriptor);

            return(areaPrefix);
        }
Beispiel #7
0
        private static string GetAreaName(RouteAreaAttribute routeAreaAttribute, Type controllerType)
        {
            if (routeAreaAttribute == null)
            {
                return(null);
            }

            // If given an area name, then use it.
            // Otherwise, use the last section of the namespace of the controller, as a convention.
            return(routeAreaAttribute.AreaName ?? controllerType.GetConventionalAreaName());
        }
Beispiel #8
0
        private string GetAreaSubdomain(RouteAreaAttribute routeAreaAttribute)
        {
            if (routeAreaAttribute == null)
            {
                return(null);
            }

            // Check for a subdomain override specified via configuration object.
            var subdomainOverride = (from o in _configuration.AreaSubdomainOverrides
                                     where o.Key == routeAreaAttribute.AreaName
                                     select o.Value).FirstOrDefault();

            return(subdomainOverride ?? routeAreaAttribute.Subdomain);
        }
        /// <summary>
        /// Gets the area URL prefix.
        /// </summary>
        /// <param name="routeAreaAttribute">The <see cref="RouteAreaAttribute"/> for the controller.</param>
        /// <param name="subdomain">The configured subdomain for the area.</param>
        /// <returns>The URL prefix for the area.</returns>
        private static string GetAreaUrl(RouteAreaAttribute routeAreaAttribute, string subdomain)
        {
            if (routeAreaAttribute == null)
                return null;

            // If a subdomain is specified for the area either in the RouteAreaAttribute
            // or via configuration, then assume the area url is blank; eg: admin.badass.com.
            // However, our fearless coder can decide to explicitly specify an area url if desired;
            // eg: internal.badass.com/admin.
            if (subdomain.HasValue() && routeAreaAttribute.AreaUrl.HasNoValue())
                return null;

            return routeAreaAttribute.AreaUrl ?? routeAreaAttribute.AreaName;
        }
        private static string GetAreaUrl(RouteAreaAttribute routeAreaAttribute)
        {
            if (routeAreaAttribute == null)
            {
                return(null);
            }

            // If a subdomain is specified for the area, then assume the area url is blank;
            // eg: admin.badass.com.
            // However, our fearless coder can decide to explicitly specify an area url if desired;
            // eg: internal.badass.com/admin.
            if (routeAreaAttribute.Subdomain.HasValue() && routeAreaAttribute.AreaUrl.HasNoValue())
            {
                return(null);
            }

            return(routeAreaAttribute.AreaUrl ?? routeAreaAttribute.AreaName);
        }
        internal static void AddRouteEntries(SubRouteCollection collector,
            ReflectedAsyncControllerDescriptor controller, IInlineConstraintResolver constraintResolver)
        {
            string prefix = GetRoutePrefix(controller);

            RouteAreaAttribute area = controller.GetAreaFrom();
            string areaName = controller.GetAreaName(area);
            string areaPrefix = area != null ? area.AreaPrefix ?? area.AreaName : null;
            ValidateAreaPrefixTemplate(areaPrefix, areaName, controller);

            AsyncActionMethodSelector actionSelector = controller.Selector;

            foreach (var method in actionSelector.DirectRouteMethods)
            {
                ActionDescriptor action = CreateActionDescriptor(controller, actionSelector, method);

                IEnumerable<IDirectRouteFactory> factories = GetRouteFactories(method, controller.ControllerType);

                AddRouteEntries(collector, areaPrefix, prefix, factories, new ActionDescriptor[] { action },
                    constraintResolver, targetIsAction: true);
            }

            // Check for controller-level routes. 
            List<ActionDescriptor> actionsWithoutRoutes = new List<ActionDescriptor>();

            foreach (var method in actionSelector.StandardRouteMethods)
            {
                ActionDescriptor action = CreateActionDescriptor(controller, actionSelector, method);

                actionsWithoutRoutes.Add(action);
            }

            IReadOnlyCollection<IDirectRouteFactory> controllerFactories = GetRouteFactories(controller);

            // If they exist and have not been overridden, create routes for controller-level route providers.
            if (controllerFactories.Count > 0 && actionsWithoutRoutes.Count > 0)
            {
                AddRouteEntries(collector, areaPrefix, prefix, controllerFactories, actionsWithoutRoutes,
                    constraintResolver, targetIsAction: false);
            }
        }
Beispiel #12
0
        private static string GetAreaUrl(RouteAreaAttribute routeAreaAttribute, string subdomain, Type controllerType)
        {
            if (routeAreaAttribute == null)
            {
                return(null);
            }

            // If a subdomain is specified for the area either in the RouteAreaAttribute
            // or via configuration, then assume the area url is blank; eg: admin.badass.com.
            // However, our fearless coder can decide to explicitly specify an area url if desired;
            // eg: internal.badass.com/admin.
            if (subdomain.HasValue() && routeAreaAttribute.AreaUrl.HasNoValue())
            {
                return(null);
            }

            // If we're given an area url or an area name, then use it.
            // Otherwise, get the area name from the namespace of the controller, as a convention.
            var areaUrlOrName = routeAreaAttribute.AreaUrl ?? routeAreaAttribute.AreaName;

            return(areaUrlOrName ?? controllerType.GetConventionalAreaName());
        }
        private static string GetAreaName(ReflectedAsyncControllerDescriptor controllerDescriptor, RouteAreaAttribute area)
        {
            if (area == null)
            {
                return null;
            }

            if (area.AreaName != null)
            {
                return area.AreaName;
            }
            if (controllerDescriptor.ControllerType.Namespace != null)
            {
                return controllerDescriptor.ControllerType.Namespace.Split('.').Last();
            }

            throw Error.InvalidOperation(MvcResources.AttributeRouting_CouldNotInferAreaNameFromMissingNamespace, controllerDescriptor.ControllerName);
        }
        /// <summary>
        /// Builds an <see cref="Route"/> for a particular controller.
        /// </summary>
        /// <param name="routeTemplate">The tokenized route template for the route.</param>
        /// <param name="routeInfoProvider">The info provider for the route.</param>
        /// <param name="controllerDescriptor">The controller the route attribute has been applied on.</param>
        /// <param name="actionDescriptors">The actions reachable by this route.</param>
        /// <param name="routeIsForAction">Whether or not the direct route is for an action.</param>
        /// <returns>The generated <see cref="Route"/>.</returns>
        public Route BuildDirectRoute(
            string routeTemplate,
            IRouteInfoProvider routeInfoProvider,
            ControllerDescriptor controllerDescriptor,
            IEnumerable <ActionDescriptor> actionDescriptors,
            bool routeIsForAction)
        {
            if (routeTemplate == null)
            {
                throw Error.ArgumentNull("routeTemplate");
            }

            if (routeInfoProvider == null)
            {
                throw Error.ArgumentNull("routeInfoProvider");
            }

            if (controllerDescriptor == null)
            {
                throw Error.ArgumentNull("controllerDescriptor");
            }

            if (actionDescriptors == null || !actionDescriptors.Any())
            {
                throw Error.ParameterCannotBeNullOrEmpty("actionDescriptors");
            }

            string controllerName = controllerDescriptor.ControllerName;

            RouteAreaAttribute area     = controllerDescriptor.GetAreaFrom();
            string             areaName = controllerDescriptor.GetAreaName(area);

            RouteValueDictionary defaults = new RouteValueDictionary
            {
                { "controller", controllerName }
            };

            if (routeIsForAction)
            {
                ActionDescriptor actionDescriptor = actionDescriptors.Single();
                defaults.Add("action", actionDescriptor.ActionName);
            }

            RouteValueDictionary constraints = new RouteValueDictionary();

            string      detokenizedRouteTemplate = InlineRouteTemplateParser.ParseRouteTemplate(routeTemplate, defaults, constraints, ConstraintResolver);
            ParsedRoute parsedRoute = RouteParser.Parse(detokenizedRouteTemplate);

            RouteValueDictionary dataTokens = new RouteValueDictionary();

            dataTokens[RouteDataTokenKeys.DirectRoutePrecedence] = RoutePrecedence.Compute(parsedRoute, constraints);
            dataTokens[RouteDataTokenKeys.DirectRouteController] = controllerDescriptor;
            dataTokens[RouteDataTokenKeys.DirectRouteActions]    = actionDescriptors;

            int order = 0;
            IOrderedRouteInfoProvider orderedAttribute = routeInfoProvider as IOrderedRouteInfoProvider;

            if (orderedAttribute != null)
            {
                order = orderedAttribute.Order;
            }

            dataTokens[RouteDataTokenKeys.DirectRouteOrder] = order;

            if (areaName != null)
            {
                dataTokens.Add(RouteDataTokenKeys.Area, areaName);
                dataTokens.Add(RouteDataTokenKeys.UseNamespaceFallback, value: false);

                Type controllerType = controllerDescriptor.ControllerType;
                if (controllerType != null)
                {
                    dataTokens.Add(RouteDataTokenKeys.Namespaces, new[] { controllerType.Namespace });
                }
            }

            Route route = new Route(detokenizedRouteTemplate, new MvcRouteHandler())
            {
                Defaults    = defaults,
                Constraints = constraints,
                DataTokens  = dataTokens
            };

            return(route);
        }
        private string GetAreaSubdomain(RouteAreaAttribute routeAreaAttribute)
        {
            if (routeAreaAttribute == null)
            {
                return null;
            }

            // Check for a subdomain override specified via configuration object.
            var subdomainOverride = (from o in _configuration.AreaSubdomainOverrides
                                     where o.Key == routeAreaAttribute.AreaName
                                     select o.Value).FirstOrDefault();

            return subdomainOverride ?? routeAreaAttribute.Subdomain;
        }
        private static string GetAreaUrl(RouteAreaAttribute routeAreaAttribute, string subdomain, Type controllerType)
        {
            if (routeAreaAttribute == null)
            {
                return null;
            }

            // If a subdomain is specified for the area either in the RouteAreaAttribute
            // or via configuration, then assume the area url is blank; eg: admin.badass.com.
            // However, our fearless coder can decide to explicitly specify an area url if desired;
            // eg: internal.badass.com/admin.
            if (subdomain.HasValue() && routeAreaAttribute.AreaUrl.HasNoValue())
            {
                return null;
            }

            // If we're given an area url or an area name, then use it.
            // Otherwise, get the area name from the namespace of the controller, as a convention.
            var areaUrlOrName = routeAreaAttribute.AreaUrl ?? routeAreaAttribute.AreaName;
            return areaUrlOrName ?? controllerType.GetConventionalAreaName();
        }
Beispiel #17
0
        internal List <RouteEntry> MapMvcAttributeRoutes(ReflectedAsyncControllerDescriptor controllerDescriptor)
        {
            string prefix = controllerDescriptor.GetPrefixFrom();

            ValidatePrefixTemplate(prefix, controllerDescriptor);

            RouteAreaAttribute area       = controllerDescriptor.GetAreaFrom();
            string             areaName   = controllerDescriptor.GetAreaName(area);
            string             areaPrefix = area != null ? area.AreaPrefix ?? area.AreaName : null;

            ValidateAreaPrefixTemplate(areaPrefix, areaName, controllerDescriptor);

            string controllerName = controllerDescriptor.ControllerName;

            AsyncActionMethodSelector actionSelector    = controllerDescriptor.Selector;
            IEnumerable <MethodInfo>  actionMethodsInfo = actionSelector.DirectRouteMethods;

            List <RouteEntry> routeEntries = new List <RouteEntry>();

            foreach (var method in actionMethodsInfo)
            {
                string actionName = actionSelector.GetActionName(method);
                IEnumerable <IRouteInfoProvider> routeAttributes = GetRouteAttributes(method, controllerDescriptor.ControllerType);

                IEnumerable <string> verbs = GetActionVerbs(method);

                foreach (var routeAttribute in routeAttributes)
                {
                    ValidateTemplate(routeAttribute.Template, actionName, controllerDescriptor);

                    string template = CombinePrefixAndAreaWithTemplate(areaPrefix, prefix, routeAttribute.Template);
                    Route  route    = _routeBuilder.BuildDirectRoute(template, verbs, controllerName,
                                                                     actionName, method, areaName);
                    RouteEntry entry = new RouteEntry
                    {
                        Name        = routeAttribute.Name,
                        Route       = route,
                        Template    = template,
                        ParsedRoute = RouteParser.Parse(route.Url),
                        HasVerbs    = verbs.Any()
                    };
                    routeEntries.Add(entry);
                }
            }

            // Check for controller-level routes.
            IEnumerable <IRouteInfoProvider> controllerRouteAttributes = controllerDescriptor.GetDirectRoutes();

            foreach (var routeAttribute in controllerRouteAttributes)
            {
                string template = CombinePrefixAndAreaWithTemplate(areaPrefix, prefix, routeAttribute.Template);

                Route      route = _routeBuilder.BuildDirectRoute(template, controllerDescriptor);
                RouteEntry entry = new RouteEntry
                {
                    Name        = routeAttribute.Name,
                    Route       = route,
                    Template    = template,
                    ParsedRoute = RouteParser.Parse(route.Url)
                };
                routeEntries.Add(entry);
            }

            return(routeEntries);
        }
Beispiel #18
0
        private static string GetAreaName(ReflectedAsyncControllerDescriptor controllerDescriptor, RouteAreaAttribute area)
        {
            if (area == null)
            {
                return(null);
            }

            if (area.AreaName != null)
            {
                return(area.AreaName);
            }
            if (controllerDescriptor.ControllerType.Namespace != null)
            {
                return(controllerDescriptor.ControllerType.Namespace.Split('.').Last());
            }

            throw Error.InvalidOperation(MvcResources.AttributeRouting_CouldNotInferAreaNameFromMissingNamespace, controllerDescriptor.ControllerName);
        }
Beispiel #19
0
        /// <inheritdoc/>
        public virtual RouteEntry Build()
        {
            if (ParsedRoute == null)
            {
                ParsedRoute = RouteParser.Parse(Template);
            }

            ValidateParameters(ParsedRoute);

            TRouteDictionaryConcrete defaults;

#if ASPNETWEBAPI
            defaults = Copy(Defaults);
#else
            defaults = Copy(Defaults) ?? new RouteValueDictionary();
#endif
            TRouteDictionaryConcrete constraints = Copy(Constraints);
            TRouteDictionaryConcrete dataTokens  =
                Copy(DataTokens) ?? new TRouteDictionaryConcrete();

            dataTokens[RouteDataTokenKeys.Actions] = _actions;

#if ASPNETWEBAPI
            if (!TargetIsAction)
            {
                dataTokens[RouteDataTokenKeys.Controller] = _actions[0].ControllerDescriptor;
            }
#endif

            int order = Order;

            if (order != default(int))
            {
                dataTokens[RouteDataTokenKeys.Order] = order;
            }

            decimal precedence = Precedence;

            if (precedence != default(decimal))
            {
                dataTokens[RouteDataTokenKeys.Precedence] = precedence;
            }

#if ASPNETWEBAPI
            if (constraints != null)
            {
                foreach (var constraint in constraints)
                {
                    HttpRoute.ValidateConstraint(Template, constraint.Key, constraint.Value);
                }
            }

            HttpMessageHandler handler = null;
            IHttpRoute         route   = new HttpRoute(
                Template,
                defaults,
                constraints,
                dataTokens,
                handler,
                ParsedRoute
                );
#else
            ControllerDescriptor controllerDescriptor = GetControllerDescriptor();

            if (controllerDescriptor != null)
            {
                defaults["controller"] = controllerDescriptor.ControllerName;
            }

            if (TargetIsAction && _actions.Length == 1)
            {
                ActionDescriptor actionDescriptor = _actions[0];
                defaults["action"] = actionDescriptor.ActionName;

                dataTokens[RouteDataTokenKeys.TargetIsAction] = true;
            }

            RouteAreaAttribute area     = controllerDescriptor.GetAreaFrom();
            string             areaName = controllerDescriptor.GetAreaName(area);

            if (areaName != null)
            {
                dataTokens[RouteDataTokenKeys.Area] = areaName;
                dataTokens[RouteDataTokenKeys.UseNamespaceFallback] = false;

                Type controllerType = controllerDescriptor.ControllerType;

                if (controllerType != null)
                {
                    dataTokens[RouteDataTokenKeys.Namespaces] = new[] { controllerType.Namespace };
                }
            }

            Route route = new Route(
                Template,
                defaults,
                constraints,
                dataTokens,
                routeHandler: null
                );

            ConstraintValidation.Validate(route);
#endif

            return(new RouteEntry(Name, route));
        }
        /// <summary>
        /// Builds a <see cref="RouteSpecification"/> from component parts.
        /// </summary>
        /// <param name="controllerIndex">The index of this controller inthe registered controller types.</param>
        /// <param name="controllerType">The controller type.</param>
        /// <param name="actionMethod">The action method info.</param>
        /// <param name="routeAreaAttribute">An applicable <see cref="RouteAreaAttribute"/> for the controller.</param>
        /// <param name="routePrefixAttribute">An applicable <see cref="RoutePrefixAttribute"/> for the controller.</param>
        /// <param name="routeAttribute">The <see cref="IRouteAttribute"/> for the action.</param>
        /// <returns>The route specification.</returns>
        private RouteSpecification BuildRouteSpecification(int controllerIndex, Type controllerType, MethodInfo actionMethod, RouteAreaAttribute routeAreaAttribute, RoutePrefixAttribute routePrefixAttribute, IRouteAttribute routeAttribute, RouteVersionedAttribute routeVersionedAttribute)
        {
            var isAsyncController = controllerType.IsAsyncController();
            var subdomain = GetAreaSubdomain(routeAreaAttribute);
            var actionName = GetActionName(actionMethod, isAsyncController);

            return new RouteSpecification
            {
                ActionMethod = actionMethod,
                ActionName = actionName,
                ActionPrecedence = GetSortableOrder(routeAttribute.ActionPrecedence),
                AppendTrailingSlash = routeAttribute.AppendTrailingSlashFlag,
                AreaName = GetAreaName(routeAreaAttribute, controllerType),
                AreaUrl = GetAreaUrl(routeAreaAttribute, subdomain, controllerType),
                AreaUrlTranslationKey = routeAreaAttribute.SafeGet(a => a.TranslationKey),
                ControllerIndex = controllerIndex,
                ControllerName = controllerType.GetControllerName(),
                ControllerPrecedence = GetSortableOrder(routeAttribute.ControllerPrecedence),
                ControllerType = controllerType,
                HttpMethods = routeAttribute.HttpMethods,
                IgnoreAreaUrl = routeAttribute.IgnoreAreaUrl,
                IgnoreRoutePrefix = routeAttribute.IgnoreRoutePrefix,
                IsAbsoluteUrl = routeAttribute.IsAbsoluteUrl,
                PrefixPrecedence = GetSortableOrder(routePrefixAttribute.SafeGet(a => a.Precedence, int.MaxValue)),
                PreserveCaseForUrlParameters = routeAttribute.PreserveCaseForUrlParametersFlag,
                RouteName = routeAttribute.RouteName,
                RoutePrefixUrl = GetRoutePrefixUrl(routePrefixAttribute, controllerType),
                RoutePrefixUrlTranslationKey = routePrefixAttribute.SafeGet(a => a.TranslationKey),
                RouteUrl = routeAttribute.RouteUrl ?? actionName,
                RouteUrlTranslationKey = routeAttribute.TranslationKey,
                SitePrecedence = GetSortableOrder(routeAttribute.SitePrecedence),
                Subdomain = subdomain,
                UseLowercaseRoute = routeAttribute.UseLowercaseRouteFlag,
                IsVersioned = routeVersionedAttribute != null && routeVersionedAttribute.IsVersioned,
                MinVersion = routeAttribute.MinVersion ?? (routeVersionedAttribute != null ? routeVersionedAttribute.MinVersion : null),
                MaxVersion = routeAttribute.MaxVersion ?? (routeVersionedAttribute != null ? routeVersionedAttribute.MaxVersion : null)
            };
        }
        internal List <RouteEntry> MapMvcAttributeRoutes(ReflectedAsyncControllerDescriptor controllerDescriptor)
        {
            string prefix = controllerDescriptor.GetPrefixFrom();

            ValidatePrefixTemplate(prefix, controllerDescriptor);

            RouteAreaAttribute area       = controllerDescriptor.GetAreaFrom();
            string             areaName   = controllerDescriptor.GetAreaName(area);
            string             areaPrefix = area != null ? area.AreaPrefix ?? area.AreaName : null;

            ValidateAreaPrefixTemplate(areaPrefix, areaName, controllerDescriptor);

            AsyncActionMethodSelector actionSelector    = controllerDescriptor.Selector;
            IEnumerable <MethodInfo>  actionMethodsInfo = actionSelector.DirectRouteMethods;

            List <RouteEntry> routeEntries = new List <RouteEntry>();

            foreach (var method in actionMethodsInfo)
            {
                string actionName = actionSelector.GetActionName(method);
                ActionDescriptorCreator creator = actionSelector.GetActionDescriptorDelegate(method);
                Debug.Assert(creator != null);

                ActionDescriptor actionDescriptor = creator(actionName, controllerDescriptor);

                IEnumerable <IRouteInfoProvider> routeAttributes = GetRouteAttributes(method, controllerDescriptor.ControllerType);

                foreach (var routeAttribute in routeAttributes)
                {
                    ValidateTemplate(routeAttribute.Template, actionName, controllerDescriptor);

                    string template = CombinePrefixAndAreaWithTemplate(areaPrefix, prefix, routeAttribute.Template);
                    Route  route    = _routeBuilder.BuildDirectRoute(template, routeAttribute, controllerDescriptor, actionDescriptor);

                    RouteEntry entry = new RouteEntry
                    {
                        Name     = routeAttribute.Name,
                        Route    = route,
                        Template = template,
                    };

                    routeEntries.Add(entry);
                }
            }

            // Check for controller-level routes.
            IEnumerable <IRouteInfoProvider> controllerRouteAttributes = controllerDescriptor.GetDirectRoutes();

            List <ActionDescriptor> actions = new List <ActionDescriptor>();

            foreach (var actionMethod in actionSelector.StandardRouteMethods)
            {
                string actionName = actionSelector.GetActionName(actionMethod);
                ActionDescriptorCreator creator = actionSelector.GetActionDescriptorDelegate(actionMethod);
                Debug.Assert(creator != null);

                ActionDescriptor actionDescriptor = creator(actionName, controllerDescriptor);
                actions.Add(actionDescriptor);
            }

            // Don't create a route for the controller-level attributes if no actions could possibly match
            if (actions.Any())
            {
                foreach (var routeAttribute in controllerRouteAttributes)
                {
                    string template = CombinePrefixAndAreaWithTemplate(areaPrefix, prefix, routeAttribute.Template);

                    Route      route = _routeBuilder.BuildDirectRoute(template, routeAttribute, controllerDescriptor, actions);
                    RouteEntry entry = new RouteEntry
                    {
                        Name     = routeAttribute.Name,
                        Route    = route,
                        Template = template,
                    };

                    routeEntries.Add(entry);
                }
            }

            return(routeEntries);
        }