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; } }
/// <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); }
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); }
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()); }
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); } }
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(); }
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); }
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); }
/// <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); }