/// <summary>
		/// Processes one attribute route
		/// </summary>
		/// <param name="action">Action to process</param>
		/// <returns>Route information</returns>
		private AttributeRouteInfo ProcessAttributeRoute(ControllerActionDescriptor action)
		{
			var constraint = action.RouteConstraints
				.FirstOrDefault(c => c.RouteKey == AttributeRouting.RouteGroupKey);
			if (constraint == null ||
				constraint.KeyHandling != RouteKeyHandling.RequireKey ||
				constraint.RouteValue == null)
			{
				// This can happen if an ActionDescriptor has a route template, but doesn't have one of our
				// special route group constraints. This is a good indication that the user is using a 3rd party
				// routing system, or has customized their ADs in a way that we can no longer understand them.
				//
				// We just treat this case as an 'opt-out' of our attribute routing system.
				return null;
			}

			var template = TemplateParser.Parse(action.AttributeRouteInfo.Template);

			var info = new AttributeRouteInfo
			{
				Constraints = GetConstraints(action.AttributeRouteInfo.Template, template),
                Defaults = GetDefaults(action, template),
                Optional = new List<string>(),
				Order = action.AttributeRouteInfo.Order,
				Precedence = AttributeRoutePrecedence.Compute(template),
			};
			_parser.Parse(template, info);

			return info;
		}
        public void GetApiDescription_IgnoresActionWithoutApiExplorerData()
        {
            // Arrange
            var action = new ControllerActionDescriptor();

            // Act
            var descriptions = GetApiDescriptions(action);

            // Assert
            Assert.Empty(descriptions);
        }
        private static void AddProperties(
            ControllerActionDescriptor actionDescriptor,
            ActionModel action,
            ControllerModel controller,
            ApplicationModel application)
        {
            foreach (var item in application.Properties)
            {
                actionDescriptor.Properties[item.Key] = item.Value;
            }

            foreach (var item in controller.Properties)
            {
                actionDescriptor.Properties[item.Key] = item.Value;
            }

            foreach (var item in action.Properties)
            {
                actionDescriptor.Properties[item.Key] = item.Value;
            }
        }
Exemple #4
0
        private static ControllerContext GetControllerContext(ControllerActionDescriptor descriptor = null, object model = null)
        {
            var context = new ControllerContext()
            {
                ActionDescriptor = descriptor ?? GetActionDescriptor(),
                HttpContext      = new DefaultHttpContext(),
                RouteData        = new RouteData(),
            };

            var binder = new Mock <IModelBinder>();

            binder.Setup(b => b.BindModelAsync(It.IsAny <ModelBindingContext>()))
            .Returns <ModelBindingContext>(mbc =>
            {
                return(ModelBindingResult.SuccessAsync(string.Empty, model));
            });

            context.ModelBinders.Add(binder.Object);
            context.ValueProviders.Add(new SimpleValueProvider());
            return(context);
        }
        public ControllerActionInvoker(
            [NotNull] ActionContext actionContext,
            [NotNull] IReadOnlyList <IFilterProvider> filterProviders,
            [NotNull] IControllerFactory controllerFactory,
            [NotNull] ControllerActionDescriptor descriptor,
            [NotNull] IReadOnlyList <IInputFormatter> inputFormatters,
            [NotNull] IReadOnlyList <IOutputFormatter> outputFormatters,
            [NotNull] IControllerActionArgumentBinder controllerActionArgumentBinder,
            [NotNull] IReadOnlyList <IModelBinder> modelBinders,
            [NotNull] IReadOnlyList <IModelValidatorProvider> modelValidatorProviders,
            [NotNull] IReadOnlyList <IValueProviderFactory> valueProviderFactories,
            [NotNull] IActionBindingContextAccessor actionBindingContextAccessor,
            [NotNull] ILogger logger,
            [NotNull] TelemetrySource telemetry,
            int maxModelValidationErrors)
            : base(
                actionContext,
                filterProviders,
                inputFormatters,
                outputFormatters,
                modelBinders,
                modelValidatorProviders,
                valueProviderFactories,
                actionBindingContextAccessor,
                logger,
                telemetry,
                maxModelValidationErrors)
        {
            _descriptor        = descriptor;
            _controllerFactory = controllerFactory;
            _argumentBinder    = controllerActionArgumentBinder;

            if (descriptor.MethodInfo == null)
            {
                throw new ArgumentException(
                          Resources.FormatPropertyOfTypeCannotBeNull("MethodInfo",
                                                                     typeof(ControllerActionDescriptor)),
                          "descriptor");
            }
        }
        public ControllerActionInvoker(
            [NotNull] ActionContext actionContext,
            [NotNull] IReadOnlyList<IFilterProvider> filterProviders,
            [NotNull] IControllerFactory controllerFactory,
            [NotNull] ControllerActionDescriptor descriptor,
            [NotNull] IReadOnlyList<IInputFormatter> inputFormatters,
            [NotNull] IReadOnlyList<IOutputFormatter> outputFormatters,
            [NotNull] IControllerActionArgumentBinder controllerActionArgumentBinder,
            [NotNull] IReadOnlyList<IModelBinder> modelBinders,
            [NotNull] IReadOnlyList<IModelValidatorProvider> modelValidatorProviders,
            [NotNull] IReadOnlyList<IValueProviderFactory> valueProviderFactories,
            [NotNull] IActionBindingContextAccessor actionBindingContextAccessor,
            [NotNull] ILogger logger,
            [NotNull] TelemetrySource telemetry,
            int maxModelValidationErrors)
            : base(
                  actionContext,
                  filterProviders,
                  inputFormatters,
                  outputFormatters,
                  modelBinders,
                  modelValidatorProviders,
                  valueProviderFactories,
                  actionBindingContextAccessor,
                  logger,
                  telemetry,
                  maxModelValidationErrors)
        {
            _descriptor = descriptor;
            _controllerFactory = controllerFactory;
            _argumentBinder = controllerActionArgumentBinder;

            if (descriptor.MethodInfo == null)
            {
                throw new ArgumentException(
                    Resources.FormatPropertyOfTypeCannotBeNull("MethodInfo",
                                                               typeof(ControllerActionDescriptor)),
                    "descriptor");
            }
        }
        public void CreateController_ThrowsIConstructorCannotBeActivated()
        {
            // Arrange
            var actionDescriptor = new ControllerActionDescriptor
            {
                ControllerTypeInfo = typeof(ControllerThatCannotBeActivated).GetTypeInfo()
            };
            var services    = GetServices();
            var httpContext = new DefaultHttpContext
            {
                RequestServices = services
            };
            var context = new ActionContext(httpContext, new RouteData(), actionDescriptor);
            var factory = CreateControllerFactory(new DefaultControllerActivator(new DefaultTypeActivatorCache()));

            // Act and Assert
            var exception = Assert.Throws <InvalidOperationException>(() => factory.CreateController(context));

            Assert.Equal(
                $"Unable to resolve service for type '{typeof(TestService).FullName}' while attempting to activate " +
                $"'{typeof(ControllerThatCannotBeActivated).FullName}'.",
                exception.Message);
        }
        public void CreateController_ThrowsIfControllerCannotBeActivated(Type type)
        {
            // Arrange
            var actionDescriptor = new ControllerActionDescriptor
            {
                ControllerTypeInfo = type.GetTypeInfo()
            };
            var services    = GetServices();
            var httpContext = new DefaultHttpContext
            {
                RequestServices = services
            };
            var context = new ActionContext(httpContext, new RouteData(), actionDescriptor);
            var factory = CreateControllerFactory(new DefaultControllerActivator(new DefaultTypeActivatorCache()));

            // Act and Assert
            var exception = Assert.Throws <InvalidOperationException>(() => factory.CreateController(context));

            Assert.Equal(
                $"The type '{type.FullName}' cannot be activated by '{typeof(DefaultControllerFactory).FullName}' " +
                "because it is either a value type, an interface, an abstract class or an open generic type.",
                exception.Message);
        }
        public void CreateController_SetsPropertiesFromActionContextHierarchy()
        {
            // Arrange
            var actionDescriptor = new ControllerActionDescriptor
            {
                ControllerTypeInfo = typeof(ControllerWithAttributes).GetTypeInfo()
            };
            var services    = GetServices();
            var httpContext = new DefaultHttpContext
            {
                RequestServices = services
            };
            var context = new ActionContext(httpContext, new RouteData(), actionDescriptor);
            var factory = CreateControllerFactory(new DefaultControllerActivator(new DefaultTypeActivatorCache()));

            // Act
            var result = factory.CreateController(context);

            // Assert
            var controller = Assert.IsType <ControllerWithAttributes>(result);

            Assert.Same(context, controller.ActionContext);
        }
        public void CreateController_IgnoresNonPublicProperties()
        {
            // Arrange
            var actionDescriptor = new ControllerActionDescriptor
            {
                ControllerTypeInfo = typeof(ControllerWithNonVisibleProperties).GetTypeInfo()
            };
            var services    = GetServices();
            var httpContext = new DefaultHttpContext
            {
                RequestServices = services
            };
            var context = new ActionContext(httpContext, new RouteData(), actionDescriptor);
            var factory = CreateControllerFactory(new DefaultControllerActivator(new DefaultTypeActivatorCache()));

            // Act
            var result = factory.CreateController(context);

            // Assert
            var controller = Assert.IsType <ControllerWithNonVisibleProperties>(result);

            Assert.Null(controller.ActionContext);
            Assert.Null(controller.BindingContext);
        }
        private void ActivateProperties(
            ControllerActionDescriptor actionDescriptor,
            object controller,
            IDictionary <string, object> properties)
        {
            var propertyHelpers = PropertyHelper.GetProperties(controller);

            for (var i = 0; i < actionDescriptor.BoundProperties.Count; i++)
            {
                var property = actionDescriptor.BoundProperties[i];

                PropertyHelper propertyHelper = null;
                for (var j = 0; j < propertyHelpers.Length; j++)
                {
                    if (string.Equals(propertyHelpers[j].Name, property.Name, StringComparison.Ordinal))
                    {
                        propertyHelper = propertyHelpers[j];
                        break;
                    }
                }

                object value;
                if (propertyHelper == null || !properties.TryGetValue(property.Name, out value))
                {
                    continue;
                }

                var propertyType = propertyHelper.Property.PropertyType;
                var metadata     = _modelMetadataProvider.GetMetadataForType(propertyType);

                if (propertyHelper.Property.CanWrite && propertyHelper.Property.SetMethod?.IsPublic == true)
                {
                    // Handle settable property. Do not set the property to null if the type is a non-nullable type.
                    if (value != null || metadata.IsReferenceOrNullableType)
                    {
                        propertyHelper.SetValue(controller, value);
                    }

                    continue;
                }

                if (propertyType.IsArray)
                {
                    // Do not attempt to copy values into an array because an array's length is immutable. This choice
                    // is also consistent with MutableObjectModelBinder's handling of a read-only array property.
                    continue;
                }

                var target = propertyHelper.GetValue(controller);
                if (value == null || target == null)
                {
                    // Nothing to do when source or target is null.
                    continue;
                }

                if (!metadata.IsCollectionType)
                {
                    // Not a collection model.
                    continue;
                }

                // Handle a read-only collection property.
                var propertyAddRange = CallPropertyAddRangeOpenGenericMethod.MakeGenericMethod(
                    metadata.ElementMetadata.ModelType);
                propertyAddRange.Invoke(obj: null, parameters: new[] { target, value });
            }
        }
 public TestControllerActionInvoker(
     ActionContext actionContext,
     IFilterProvider[] filterProvider,
     MockControllerFactory controllerFactory,
     ControllerActionDescriptor descriptor,
     IReadOnlyList<IInputFormatter> inputFormatters,
     IControllerActionArgumentBinder controllerActionArgumentBinder,
     IReadOnlyList<IModelBinder> modelBinders,
     IReadOnlyList<IModelValidatorProvider> modelValidatorProviders,
     IReadOnlyList<IValueProviderFactory> valueProviderFactories,
     ILogger logger,
     DiagnosticSource diagnosticSource,
     int maxAllowedErrorsInModelState)
     : base(
           actionContext,
           filterProvider,
           controllerFactory,
           descriptor,
           inputFormatters,
           controllerActionArgumentBinder,
           modelBinders,
           modelValidatorProviders,
           valueProviderFactories,
           logger,
           diagnosticSource,
           maxAllowedErrorsInModelState)
 {
     ControllerFactory = controllerFactory;
 }
		/// <summary>
		/// Processes the defaults for the specified action.
		/// </summary>
		/// <param name="action">MVC action</param>
		/// <param name="template">Route template for this action</param>
		/// <returns>Defaults for this action</returns>
		private IDictionary<string, object> GetDefaults(ControllerActionDescriptor action, RouteTemplate template)
		{
			var defaults = template.Parameters
				.Where(p => p.DefaultValue != null)
				.ToDictionary(
					p => p.Name.ToLowerInvariant(),
					p => p.DefaultValue,
					StringComparer.OrdinalIgnoreCase
				);

			defaults.Add("controller", action.ControllerName);
			defaults.Add("action", action.Name);
			return defaults;
		}
        private TestControllerActionInvoker CreateInvoker(
            IFilterMetadata[] filters,
            bool actionThrows = false,
            int maxAllowedErrorsInModelState = 200)
        {
            var actionDescriptor = new ControllerActionDescriptor()
            {
                FilterDescriptors = new List<FilterDescriptor>(),
                Parameters = new List<ParameterDescriptor>(),
            };

            if (actionThrows)
            {
                actionDescriptor.MethodInfo = typeof(ControllerActionInvokerTest).GetMethod("ThrowingActionMethod");
            }
            else
            {
                actionDescriptor.MethodInfo = typeof(ControllerActionInvokerTest).GetMethod("ActionMethod");
            }

            var httpContext = new Mock<HttpContext>(MockBehavior.Loose);

            var http = GetHttpContext();

            var httpRequest = http.Request;
            var httpResponse = http.Response;

            httpContext.SetupGet(c => c.Request).Returns(httpRequest);
            httpContext.SetupGet(c => c.Response).Returns(httpResponse);
            httpContext
                .Setup(o => o.RequestServices.GetService(typeof(ILoggerFactory)))
                .Returns(NullLoggerFactory.Instance);

            httpResponse.Body = new MemoryStream();

            var formatter = new Mock<IOutputFormatter>();
            formatter
                .Setup(f => f.CanWriteResult(It.IsAny<OutputFormatterCanWriteContext>()))
                .Returns(true);

            formatter
                .Setup(f => f.WriteAsync(It.IsAny<OutputFormatterWriteContext>()))
                .Returns<OutputFormatterWriteContext>(async c =>
                {
                    await c.HttpContext.Response.WriteAsync(c.Object.ToString());
                });

            var options = new MvcOptions();
            options.OutputFormatters.Add(formatter.Object);

            var optionsAccessor = new Mock<IOptions<MvcOptions>>();
            optionsAccessor
                .SetupGet(o => o.Value)
                .Returns(options);

            httpContext
                .Setup(o => o.RequestServices.GetService(typeof(IOptions<MvcOptions>)))
                .Returns(optionsAccessor.Object);

            var actionContext = new ActionContext(
                httpContext: httpContext.Object,
                routeData: new RouteData(),
                actionDescriptor: actionDescriptor);

            var filterProvider = new Mock<IFilterProvider>(MockBehavior.Strict);
            filterProvider
                .Setup(fp => fp.OnProvidersExecuting(It.IsAny<FilterProviderContext>()))
                .Callback<FilterProviderContext>(context =>
                    {
                        foreach (var filterMetadata in filters)
                        {
                            var filter = new FilterItem(
                                new FilterDescriptor(filterMetadata, FilterScope.Action),
                                filterMetadata);
                            context.Results.Add(filter);
                        }
                    });

            filterProvider
                .Setup(fp => fp.OnProvidersExecuted(It.IsAny<FilterProviderContext>()))
                .Verifiable();

            var actionArgumentsBinder = new Mock<IControllerActionArgumentBinder>();
            actionArgumentsBinder.Setup(
                    b => b.BindActionArgumentsAsync(It.IsAny<ControllerContext>(), It.IsAny<object>()))
                .Returns(Task.FromResult<IDictionary<string, object>>(new Dictionary<string, object>()));

            filterProvider
                .SetupGet(fp => fp.Order)
                .Returns(-1000);

            var invoker = new TestControllerActionInvoker(
                actionContext,
                new[] { filterProvider.Object },
                new MockControllerFactory(this),
                actionDescriptor,
                new IInputFormatter[0],
                actionArgumentsBinder.Object,
                new IModelBinder[0],
                new IModelValidatorProvider[0],
                new IValueProviderFactory[0],
                new NullLoggerFactory().CreateLogger<ControllerActionInvoker>(),
                new DiagnosticListener("Microsoft.AspNet"),
                maxAllowedErrorsInModelState);
            return invoker;
        }
        public async Task Invoke_UsesDefaultValuesIfNotBound()
        {
            // Arrange
            var actionDescriptor = new ControllerActionDescriptor
            {
                ControllerTypeInfo = typeof(TestController).GetTypeInfo(),
                BoundProperties = new List<ParameterDescriptor>(),
                MethodInfo = typeof(TestController).GetTypeInfo()
                    .DeclaredMethods
                    .First(m => m.Name.Equals("ActionMethodWithDefaultValues", StringComparison.Ordinal)),

                Parameters = new List<ParameterDescriptor>
                {
                    new ParameterDescriptor
                    {
                        Name = "value",
                        ParameterType = typeof(int),
                        BindingInfo = new BindingInfo(),
                    }
                },
                FilterDescriptors = new List<FilterDescriptor>()
            };

            var binder = new Mock<IModelBinder>();
            binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
                  .Returns(ModelBindingResult.NoResultAsync);
            var context = new Mock<HttpContext>();
            context.SetupGet(c => c.Items)
                   .Returns(new Dictionary<object, object>());
            context.Setup(c => c.RequestServices.GetService(typeof(ILoggerFactory)))
                       .Returns(new NullLoggerFactory());

            var actionContext = new ActionContext(context.Object, new RouteData(), actionDescriptor);

            var controllerFactory = new Mock<IControllerFactory>();
            controllerFactory.Setup(c => c.CreateController(It.IsAny<ControllerContext>()))
                             .Returns(new TestController());

            var metadataProvider = new EmptyModelMetadataProvider();

            var invoker = new ControllerActionInvoker(
                actionContext,
                new List<IFilterProvider>(),
                controllerFactory.Object,
                actionDescriptor,
                new IInputFormatter[0],
                new DefaultControllerActionArgumentBinder(
                    metadataProvider,
                    new DefaultObjectValidator(metadataProvider)),
                new IModelBinder[] { binder.Object },
                new IModelValidatorProvider[0],
                new IValueProviderFactory[0],
                new NullLoggerFactory().CreateLogger<ControllerActionInvoker>(),
                new DiagnosticListener("Microsoft.AspNet"),
                200);

            // Act
            await invoker.InvokeAsync();

            // Assert
            Assert.Equal(5, context.Object.Items["Result"]);
        }
        private ControllerActionDescriptor CreateActionDescriptor(string methodName = null, Type controllerType = null)
        {
            var action = new ControllerActionDescriptor();
            action.SetProperty(new ApiDescriptionActionData());

            if (controllerType != null)
            {
                action.MethodInfo = controllerType.GetMethod(
                    methodName ?? "ReturnsObject",
                    BindingFlags.Instance | BindingFlags.Public);

                action.ControllerTypeInfo = controllerType.GetTypeInfo();
                action.BoundProperties = new List<ParameterDescriptor>();

                foreach (var property in action.ControllerTypeInfo.GetProperties())
                {
                    var bindingInfo = BindingInfo.GetBindingInfo(property.GetCustomAttributes().OfType<object>());
                    if (bindingInfo != null)
                    {
                        action.BoundProperties.Add(new ParameterDescriptor()
                        {
                            BindingInfo = bindingInfo,
                            Name = property.Name,
                            ParameterType = property.PropertyType,
                        });
                    }
                }
            }
            else
            {
                action.MethodInfo = GetType().GetMethod(
                    methodName ?? "ReturnsObject",
                    BindingFlags.Instance | BindingFlags.NonPublic);
            }

            action.Parameters = new List<ParameterDescriptor>();
            foreach (var parameter in action.MethodInfo.GetParameters())
            {
                action.Parameters.Add(new ParameterDescriptor()
                {
                    Name = parameter.Name,
                    ParameterType = parameter.ParameterType,
                    BindingInfo = BindingInfo.GetBindingInfo(parameter.GetCustomAttributes().OfType<object>())
                });
            }

            return action;
        }
        public ControllerActionInvoker(
            ActionContext actionContext,
            IReadOnlyList<IFilterProvider> filterProviders,
            IControllerFactory controllerFactory,
            ControllerActionDescriptor descriptor,
            IReadOnlyList<IInputFormatter> inputFormatters,
            IControllerActionArgumentBinder controllerActionArgumentBinder,
            IReadOnlyList<IModelBinder> modelBinders,
            IReadOnlyList<IModelValidatorProvider> modelValidatorProviders,
            IReadOnlyList<IValueProviderFactory> valueProviderFactories,
            ILogger logger,
            DiagnosticSource diagnosticSource,
            int maxModelValidationErrors)
            : base(
                  actionContext,
                  filterProviders,
                  inputFormatters,
                  modelBinders,
                  modelValidatorProviders,
                  valueProviderFactories,
                  logger,
                  diagnosticSource,
                  maxModelValidationErrors)
        {
            if (actionContext == null)
            {
                throw new ArgumentNullException(nameof(actionContext));
            }

            if (filterProviders == null)
            {
                throw new ArgumentNullException(nameof(filterProviders));
            }

            if (controllerFactory == null)
            {
                throw new ArgumentNullException(nameof(controllerFactory));
            }

            if (descriptor == null)
            {
                throw new ArgumentNullException(nameof(descriptor));
            }

            if (inputFormatters == null)
            {
                throw new ArgumentNullException(nameof(inputFormatters));
            }

            if (controllerActionArgumentBinder == null)
            {
                throw new ArgumentNullException(nameof(controllerActionArgumentBinder));
            }

            if (modelBinders == null)
            {
                throw new ArgumentNullException(nameof(modelBinders));
            }

            if (modelValidatorProviders == null)
            {
                throw new ArgumentNullException(nameof(modelValidatorProviders));
            }

            if (valueProviderFactories == null)
            {
                throw new ArgumentNullException(nameof(valueProviderFactories));
            }

            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }

            if (diagnosticSource == null)
            {
                throw new ArgumentNullException(nameof(diagnosticSource));
            }

            _descriptor = descriptor;
            _controllerFactory = controllerFactory;
            _argumentBinder = controllerActionArgumentBinder;

            if (descriptor.MethodInfo == null)
            {
                throw new ArgumentException(
                    Resources.FormatPropertyOfTypeCannotBeNull("MethodInfo",
                                                               typeof(ControllerActionDescriptor)),
                    "descriptor");
            }
        }
 public TestControllerActionInvoker(
     ActionContext actionContext,
     IFilterProvider[] filterProvider,
     MockControllerFactory controllerFactory,
     ControllerActionDescriptor descriptor,
     IReadOnlyList<IInputFormatter> inputFormatters,
     IReadOnlyList<IOutputFormatter> outputFormatters,
     IControllerActionArgumentBinder controllerActionArgumentBinder,
     IReadOnlyList<IModelBinder> modelBinders,
     IReadOnlyList<IModelValidatorProvider> modelValidatorProviders,
     IReadOnlyList<IValueProviderFactory> valueProviderFactories,
     IActionBindingContextAccessor actionBindingContext,
     ILogger logger,
     TelemetrySource telemetry,
     int maxAllowedErrorsInModelState)
     : base(
           actionContext,
           filterProvider,
           controllerFactory,
           descriptor,
           inputFormatters,
           outputFormatters,
           controllerActionArgumentBinder,
           modelBinders,
           modelValidatorProviders,
           valueProviderFactories,
           actionBindingContext,
           logger,
           telemetry,
           maxAllowedErrorsInModelState)
 {
     ControllerFactory = controllerFactory;
 }
        public async Task AttributeRouting_WithControllerActionDescriptor()
        {
            // Arrange
            var controllerType = typeof(HomeController);
            var actionMethod = controllerType.GetMethod("Index");

            var action = new ControllerActionDescriptor();
            action.DisplayName = "Microsoft.AspNet.Mvc.Routing.AttributeRoutingTest+HomeController.Index";
            action.MethodInfo = actionMethod;
            action.RouteConstraints = new List<RouteDataActionConstraint>()
            {
                new RouteDataActionConstraint(TreeRouter.RouteGroupKey, "group"),
            };
            action.AttributeRouteInfo = new AttributeRouteInfo();
            action.AttributeRouteInfo.Template = "{controller}/{action}";

            action.RouteValueDefaults.Add("controller", "Home");
            action.RouteValueDefaults.Add("action", "Index");

            var expectedMessage =
                "The following errors occurred with attribute routing information:" + Environment.NewLine +
                Environment.NewLine +
                "For action: 'Microsoft.AspNet.Mvc.Routing.AttributeRoutingTest+HomeController.Index'" + Environment.NewLine +
                "Error: The attribute route '{controller}/{action}' cannot contain a parameter named '{controller}'. " +
                "Use '[controller]' in the route template to insert the value 'Home'.";

            var handler = CreateRouter();
            var services = CreateServices(action);

            var route = AttributeRouting.CreateAttributeMegaRoute(handler, services);

            // Act & Assert
            var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () =>
            {
                await route.RouteAsync(new RouteContext(new DefaultHttpContext()));
            });

            Assert.Equal(expectedMessage, ex.Message);
        }
        public static void AddRouteConstraints(
            ISet <string> removalConstraints,
            ControllerActionDescriptor actionDescriptor,
            ControllerModel controller,
            ActionModel action)
        {
            // Apply all the constraints defined on the action, then controller (for example, [Area])
            // to the actions. Also keep track of all the constraints that require preventing actions
            // without the constraint to match. For example, actions without an [Area] attribute on their
            // controller should not match when a value has been given for area when matching a url or
            // generating a link.
            foreach (var constraintAttribute in action.RouteConstraints)
            {
                if (constraintAttribute.BlockNonAttributedActions)
                {
                    removalConstraints.Add(constraintAttribute.RouteKey);
                }

                // Skip duplicates
                if (!HasConstraint(actionDescriptor.RouteConstraints, constraintAttribute.RouteKey))
                {
                    if (constraintAttribute.RouteKeyHandling == RouteKeyHandling.CatchAll)
                    {
                        actionDescriptor.RouteConstraints.Add(
                            RouteDataActionConstraint.CreateCatchAll(
                                constraintAttribute.RouteKey));
                    }
                    else
                    {
                        actionDescriptor.RouteConstraints.Add(new RouteDataActionConstraint(
                                                                  constraintAttribute.RouteKey,
                                                                  constraintAttribute.RouteValue));
                    }
                }
            }

            foreach (var constraintAttribute in controller.RouteConstraints)
            {
                if (constraintAttribute.BlockNonAttributedActions)
                {
                    removalConstraints.Add(constraintAttribute.RouteKey);
                }

                // Skip duplicates - this also means that a value on the action will take precedence
                if (!HasConstraint(actionDescriptor.RouteConstraints, constraintAttribute.RouteKey))
                {
                    if (constraintAttribute.RouteKeyHandling == RouteKeyHandling.CatchAll)
                    {
                        actionDescriptor.RouteConstraints.Add(
                            RouteDataActionConstraint.CreateCatchAll(
                                constraintAttribute.RouteKey));
                    }
                    else
                    {
                        actionDescriptor.RouteConstraints.Add(new RouteDataActionConstraint(
                                                                  constraintAttribute.RouteKey,
                                                                  constraintAttribute.RouteValue));
                    }
                }
            }

            // Lastly add the 'default' values
            if (!HasConstraint(actionDescriptor.RouteConstraints, "action"))
            {
                actionDescriptor.RouteConstraints.Add(new RouteDataActionConstraint(
                                                          "action",
                                                          action.ActionName ?? string.Empty));
            }

            if (!HasConstraint(actionDescriptor.RouteConstraints, "controller"))
            {
                actionDescriptor.RouteConstraints.Add(new RouteDataActionConstraint(
                                                          "controller",
                                                          controller.ControllerName));
            }
        }
 private static bool IsAttributeRoutedAction(ControllerActionDescriptor actionDescriptor)
 {
     return(actionDescriptor.AttributeRouteInfo?.Template != null);
 }
        public ControllerActionInvoker(
            ActionContext actionContext,
            IReadOnlyList <IFilterProvider> filterProviders,
            IControllerFactory controllerFactory,
            ControllerActionDescriptor descriptor,
            IReadOnlyList <IInputFormatter> inputFormatters,
            IControllerActionArgumentBinder controllerActionArgumentBinder,
            IReadOnlyList <IModelBinder> modelBinders,
            IReadOnlyList <IModelValidatorProvider> modelValidatorProviders,
            IReadOnlyList <IValueProviderFactory> valueProviderFactories,
            ILogger logger,
            DiagnosticSource diagnosticSource,
            int maxModelValidationErrors)
            : base(
                actionContext,
                filterProviders,
                inputFormatters,
                modelBinders,
                modelValidatorProviders,
                valueProviderFactories,
                logger,
                diagnosticSource,
                maxModelValidationErrors)
        {
            if (actionContext == null)
            {
                throw new ArgumentNullException(nameof(actionContext));
            }

            if (filterProviders == null)
            {
                throw new ArgumentNullException(nameof(filterProviders));
            }

            if (controllerFactory == null)
            {
                throw new ArgumentNullException(nameof(controllerFactory));
            }

            if (descriptor == null)
            {
                throw new ArgumentNullException(nameof(descriptor));
            }

            if (inputFormatters == null)
            {
                throw new ArgumentNullException(nameof(inputFormatters));
            }

            if (controllerActionArgumentBinder == null)
            {
                throw new ArgumentNullException(nameof(controllerActionArgumentBinder));
            }

            if (modelBinders == null)
            {
                throw new ArgumentNullException(nameof(modelBinders));
            }

            if (modelValidatorProviders == null)
            {
                throw new ArgumentNullException(nameof(modelValidatorProviders));
            }

            if (valueProviderFactories == null)
            {
                throw new ArgumentNullException(nameof(valueProviderFactories));
            }

            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }

            if (diagnosticSource == null)
            {
                throw new ArgumentNullException(nameof(diagnosticSource));
            }

            _descriptor        = descriptor;
            _controllerFactory = controllerFactory;
            _argumentBinder    = controllerActionArgumentBinder;

            if (descriptor.MethodInfo == null)
            {
                throw new ArgumentException(
                          Resources.FormatPropertyOfTypeCannotBeNull("MethodInfo",
                                                                     typeof(ControllerActionDescriptor)),
                          "descriptor");
            }
        }