public void CreateRouteEntry_IfDirectRouteProviderReturnsRouteWithEmptyActionDescriptors_Throws()
        {
            // Arrange
            string areaPrefix = null;
            string controllerPrefix = null;
            Route route = new Route(url: null, routeHandler: null);
            route.DataTokens = new RouteValueDictionary();
            route.DataTokens.Add(RouteDataTokenKeys.Actions, new ActionDescriptor[0]);
            ActionDescriptor[] originalActions = route.GetTargetActionDescriptors();
            Assert.NotNull(originalActions); // Guard
            Assert.Equal(0, originalActions.Length); // Guard
            RouteEntry entry = new RouteEntry(name: null, route: route);
            IDirectRouteFactory factory = CreateStubRouteFactory(entry);
            ControllerDescriptor controllerDescriptor = CreateStubControllerDescriptor("IgnoreController");
            ActionDescriptor actionDescriptor = CreateStubActionDescriptor(controllerDescriptor, "IgnoreAction");
            IReadOnlyCollection<ActionDescriptor> actions = new ActionDescriptor[] { actionDescriptor };
            IInlineConstraintResolver constraintResolver =
                new Mock<IInlineConstraintResolver>(MockBehavior.Strict).Object;

            // Act & Assert
            string expectedMessage = "The route does not have any associated action descriptors. Routing requires " +
                "that each direct route map to a non-empty set of actions.";
            Assert.Throws<InvalidOperationException>(() => DefaultDirectRouteProvider.CreateRouteEntry(areaPrefix,
                controllerPrefix, factory, actions, constraintResolver, targetIsAction: false), expectedMessage);
        }
        internal List<RouteEntry> MapMvcAttributeRoutes(ReflectedAsyncControllerDescriptor controllerDescriptor)
        {
            string prefix = GetPrefixFrom(controllerDescriptor);
            ValidatePrefixTemplate(prefix, 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 = GetActionName(method, actionSelector.AllowLegacyAsyncActions);
                IEnumerable<IDirectRouteInfoProvider> routeAttributes = GetRouteAttributes(method);

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

                    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,
                        Route = route,
                        Template = template,
                        ParsedRoute = RouteParser.Parse(route.Url),
                        Order = routeAttribute.RouteOrder                        
                    };
                    routeEntries.Add(entry);                    
                }
            }

            return routeEntries;
        }
        public void CreateRouteEntry_IfDirectRouteProviderReturnsRouteWithHandler_Throws()
        {
            // Arrange
            string areaPrefix = null;
            string controllerPrefix = null;
            ControllerDescriptor controllerDescriptor = CreateStubControllerDescriptor("IgnoreController");
            ActionDescriptor actionDescriptor = CreateStubActionDescriptor(controllerDescriptor, "IgnoreAction");
            Route route = new Route(url: null, routeHandler: null);
            route.DataTokens = new RouteValueDictionary();
            route.DataTokens.Add(RouteDataTokenKeys.Actions, new ActionDescriptor[] { actionDescriptor });
            route.RouteHandler = new Mock<IRouteHandler>(MockBehavior.Strict).Object;
            ActionDescriptor[] originalActions = route.GetTargetActionDescriptors();
            RouteEntry entry = new RouteEntry(name: null, route: route);
            IDirectRouteFactory factory = CreateStubRouteFactory(entry);
            IReadOnlyCollection<ActionDescriptor> actions = new ActionDescriptor[] { actionDescriptor };
            IInlineConstraintResolver constraintResolver =
                new Mock<IInlineConstraintResolver>(MockBehavior.Strict).Object;

            // Act & Assert
            string expectedMessage = "Direct routing does not support per-route route handlers.";
            Assert.Throws<InvalidOperationException>(() => DefaultDirectRouteProvider.CreateRouteEntry(areaPrefix,
                controllerPrefix, factory, actions, constraintResolver, targetIsAction: false), expectedMessage);
        }
 private static IDirectRouteFactory CreateStubRouteFactory(RouteEntry entry)
 {
     Mock<IDirectRouteFactory> mock = new Mock<IDirectRouteFactory>(MockBehavior.Strict);
     mock.Setup(p => p.CreateRoute(It.IsAny<DirectRouteFactoryContext>())).Returns(entry);
     return mock.Object;
 }