Пример #1
0
        private static void AddActionToNamedGroup(
            IDictionary <string, IList <ActionDescriptor> > actionsByRouteName,
            string routeName,
            ReflectedActionDescriptor actionDescriptor)
        {
            IList <ActionDescriptor> namedActionGroup;

            if (actionsByRouteName.TryGetValue(routeName, out namedActionGroup))
            {
                namedActionGroup.Add(actionDescriptor);
            }
            else
            {
                namedActionGroup = new List <ActionDescriptor>();
                namedActionGroup.Add(actionDescriptor);
                actionsByRouteName.Add(routeName, namedActionGroup);
            }
        }
Пример #2
0
 public ReflectedActionInvoker([NotNull] ActionContext actionContext,
                               [NotNull] IActionBindingContextProvider bindingContextProvider,
                               [NotNull] INestedProviderManager <FilterProviderContext> filterProvider,
                               [NotNull] IControllerFactory controllerFactory,
                               [NotNull] ReflectedActionDescriptor descriptor,
                               [NotNull] IInputFormattersProvider inputFormattersProvider)
     : base(actionContext, bindingContextProvider, filterProvider)
 {
     _descriptor              = descriptor;
     _controllerFactory       = controllerFactory;
     _inputFormattersProvider = inputFormattersProvider;
     if (descriptor.MethodInfo == null)
     {
         throw new ArgumentException(
                   Resources.FormatPropertyOfTypeCannotBeNull("MethodInfo",
                                                              typeof(ReflectedActionDescriptor)),
                   "descriptor");
     }
 }
Пример #3
0
        private static void ReplaceAttributeRouteTokens(
            ReflectedActionDescriptor actionDescriptor,
            IList <string> routeTemplateErrors)
        {
            try
            {
                actionDescriptor.AttributeRouteInfo.Template = ReflectedAttributeRouteModel.ReplaceTokens(
                    actionDescriptor.AttributeRouteInfo.Template,
                    actionDescriptor.RouteValueDefaults);
            }
            catch (InvalidOperationException ex)
            {
                var message = Resources.FormatAttributeRoute_IndividualErrorMessage(
                    actionDescriptor.DisplayName,
                    Environment.NewLine,
                    ex.Message);

                routeTemplateErrors.Add(message);
            }
        }
        public List<ReflectedActionDescriptor> Build(ReflectedApplicationModel model)
        {
            var actions = new List<ReflectedActionDescriptor>();

            var routeGroupsByTemplate = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            var removalConstraints = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

            var routeTemplateErrors = new List<string>();

            foreach (var controller in model.Controllers)
            {
                var controllerDescriptor = new ControllerDescriptor(controller.ControllerType);
                foreach (var action in controller.Actions)
                {
                    var parameterDescriptors = new List<ParameterDescriptor>();
                    foreach (var parameter in action.Parameters)
                    {
                        var isFromBody = parameter.Attributes.OfType<FromBodyAttribute>().Any();

                        parameterDescriptors.Add(new ParameterDescriptor()
                        {
                            Name = parameter.ParameterName,
                            IsOptional = parameter.IsOptional,

                            ParameterBindingInfo = isFromBody
                                ? null
                                : new ParameterBindingInfo(
                                    parameter.ParameterName,
                                    parameter.ParameterInfo.ParameterType),

                            BodyParameterInfo = isFromBody
                                ? new BodyParameterInfo(parameter.ParameterInfo.ParameterType)
                                : null
                        });
                    }

                    var actionDescriptor = new ReflectedActionDescriptor()
                    {
                        Name = action.ActionName,
                        ControllerDescriptor = controllerDescriptor,
                        MethodInfo = action.ActionMethod,
                        Parameters = parameterDescriptors,
                        RouteConstraints = new List<RouteDataActionConstraint>(),
                    };

                    actionDescriptor.DisplayName = string.Format(
                        "{0}.{1}",
                        action.ActionMethod.DeclaringType.FullName,
                        action.ActionMethod.Name);

                    var httpMethods = action.HttpMethods;
                    if (httpMethods != null && httpMethods.Count > 0)
                    {
                        actionDescriptor.MethodConstraints = new List<HttpMethodConstraint>()
                        {
                            new HttpMethodConstraint(httpMethods)
                        };
                    }

                    actionDescriptor.RouteConstraints.Add(new RouteDataActionConstraint(
                        "controller",
                        controller.ControllerName));

                    if (action.IsActionNameMatchRequired)
                    {
                        actionDescriptor.RouteConstraints.Add(new RouteDataActionConstraint(
                            "action",
                            action.ActionName));
                    }
                    else
                    {
                        actionDescriptor.RouteConstraints.Add(new RouteDataActionConstraint(
                            "action",
                            RouteKeyHandling.DenyKey));
                    }

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

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

                    var templateText = AttributeRouteTemplate.Combine(
                            controller.RouteTemplate,
                            action.RouteTemplate);

                    if (templateText != null)
                    {
                        // An attribute routed action will ignore conventional routed constraints. We still
                        // want to provide these values as ambient values.
                        foreach (var constraint in actionDescriptor.RouteConstraints)
                        {
                            actionDescriptor.RouteValueDefaults.Add(constraint.RouteKey, constraint.RouteValue);
                        }

                        // Replaces tokens like [controller]/[action] in the route template with the actual values
                        // for this action.
                        try
                        {
                            templateText = AttributeRouteTemplate.ReplaceTokens(
                                templateText,
                                actionDescriptor.RouteValueDefaults);
                        }
                        catch (InvalidOperationException ex)
                        {
                            var message = Resources.FormatAttributeRoute_IndividualErrorMessage(
                                actionDescriptor.DisplayName,
                                Environment.NewLine,
                                ex.Message);

                            routeTemplateErrors.Add(message);
                        }

                        actionDescriptor.AttributeRouteTemplate = templateText;

                        // An attribute routed action is matched by its 'route group' which identifies all equivalent
                        // actions.
                        string routeGroup;
                        if (!routeGroupsByTemplate.TryGetValue(templateText, out routeGroup))
                        {
                            routeGroup = GetRouteGroup(templateText);
                            routeGroupsByTemplate.Add(templateText, routeGroup);
                        }

                        var routeConstraints = new List<RouteDataActionConstraint>();
                        routeConstraints.Add(new RouteDataActionConstraint(
                            AttributeRouting.RouteGroupKey,
                            routeGroup));

                        actionDescriptor.RouteConstraints = routeConstraints;
                    }

                    actionDescriptor.FilterDescriptors =
                        action.Filters.Select(f => new FilterDescriptor(f, FilterScope.Action))
                        .Concat(controller.Filters.Select(f => new FilterDescriptor(f, FilterScope.Controller)))
                        .Concat(model.Filters.Select(f => new FilterDescriptor(f, FilterScope.Global)))
                        .OrderBy(d => d, FilterDescriptorOrderComparer.Comparer)
                        .ToList();

                    actions.Add(actionDescriptor);
                }
            }

            foreach (var actionDescriptor in actions)
            {
                foreach (var key in removalConstraints)
                {
                    if (actionDescriptor.AttributeRouteTemplate == null)
                    {
                        // Any any attribute routes are in use, then non-attribute-routed ADs can't be selected
                        // when a route group returned by the route.
                        if (routeGroupsByTemplate.Any())
                        {
                            actionDescriptor.RouteConstraints.Add(new RouteDataActionConstraint(
                                AttributeRouting.RouteGroupKey,
                                RouteKeyHandling.DenyKey));
                        }

                        if (!HasConstraint(actionDescriptor.RouteConstraints, key))
                        {
                            actionDescriptor.RouteConstraints.Add(new RouteDataActionConstraint(
                                key,
                                RouteKeyHandling.DenyKey));
                        }
                    }
                    else
                    {
                        // We still want to add a 'null' for any constraint with DenyKey so that link generation
                        // works properly.
                        //
                        // Consider an action like { area = "", controller = "Home", action = "Index" }. Even if
                        // it's attribute routed, it needs to know that area must be null to generate a link.
                        if (!actionDescriptor.RouteValueDefaults.ContainsKey(key))
                        {
                            actionDescriptor.RouteValueDefaults.Add(key, null);
                        }
                    }
                }
            }

            if (routeTemplateErrors.Any())
            {
                var message = Resources.FormatAttributeRoute_AggregateErrorMessage(
                    Environment.NewLine,
                    string.Join(Environment.NewLine + Environment.NewLine, routeTemplateErrors));
                throw new InvalidOperationException(message);
            }

            return actions;
        }
Пример #5
0
        public async Task Invoke_UsesDefaultValuesIfNotBound()
        {
            // Arrange
            var actionDescriptor = new ReflectedActionDescriptor
            {
                MethodInfo = typeof(TestController).GetTypeInfo()
                                                               .DeclaredMethods
                                                               .First(m => m.Name.Equals("ActionMethodWithDefaultValues", StringComparison.Ordinal)),
                Parameters = new List<ParameterDescriptor>
                            {
                                new ParameterDescriptor
                                {
                                    Name = "value",
                                    ParameterBindingInfo = new ParameterBindingInfo("value", typeof(int))
                                }
                            },
                FilterDescriptors = new List<FilterDescriptor>()
            };

            var binder = new Mock<IModelBinder>();
            var metadataProvider = new EmptyModelMetadataProvider();
            binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
                  .Returns(Task.FromResult(result: false));
            var context = new Mock<HttpContext>();
            context.SetupGet(c => c.Items)
                   .Returns(new Dictionary<object, object>());
            var routeContext = new RouteContext(context.Object);
            var actionContext = new ActionContext(routeContext,
                                                  actionDescriptor);
            var bindingContext = new ActionBindingContext(actionContext,
                                                          Mock.Of<IModelMetadataProvider>(),
                                                          binder.Object,
                                                          Mock.Of<IValueProvider>(),
                                                          Mock.Of<IInputFormatterProvider>(),
                                                          Enumerable.Empty<IModelValidatorProvider>());

            var actionBindingContextProvider = new Mock<IActionBindingContextProvider>();
            actionBindingContextProvider.Setup(p => p.GetActionBindingContextAsync(It.IsAny<ActionContext>()))
                                        .Returns(Task.FromResult(bindingContext));
            var controllerFactory = new Mock<IControllerFactory>();
            controllerFactory.Setup(c => c.CreateController(It.IsAny<ActionContext>()))
                             .Returns(new TestController());

            var invoker = new ReflectedActionInvoker(actionContext,
                                                     actionDescriptor,
                                                     controllerFactory.Object,
                                                     actionBindingContextProvider.Object,
                                                     Mock.Of<INestedProviderManager<FilterProviderContext>>());

            // Act
            await invoker.InvokeActionAsync();

            // Assert
            Assert.Equal(5, context.Object.Items["Result"]);
        }
Пример #6
0
        public async Task GetActionArguments_AddsActionArgumentsToModelStateDictionary_IfBinderReturnsTrue()
        {
            // Arrange
            Func<object, int> method = x => 1;
            var actionDescriptor = new ReflectedActionDescriptor
            {
                MethodInfo = method.Method,
                Parameters = new List<ParameterDescriptor>
                            {
                                new ParameterDescriptor
                                {
                                    Name = "foo",
                                    ParameterBindingInfo = new ParameterBindingInfo("foo", typeof(object))
                                }
                            }
            };
            var value = "Hello world";
            var binder = new Mock<IModelBinder>();
            var metadataProvider = new EmptyModelMetadataProvider();
            binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
                  .Callback((ModelBindingContext context) =>
                  {
                      context.ModelMetadata = metadataProvider.GetMetadataForType(modelAccessor: null,
                                                                                  modelType: typeof(string));
                      context.Model = value;
                  })
                  .Returns(Task.FromResult(result: true));
            var actionContext = new ActionContext(new RouteContext(Mock.Of<HttpContext>()),
                                                  actionDescriptor);
            var bindingContext = new ActionBindingContext(actionContext,
                                                          Mock.Of<IModelMetadataProvider>(),
                                                          binder.Object,
                                                          Mock.Of<IValueProvider>(),
                                                          Mock.Of<IInputFormatterProvider>(),
                                                          Enumerable.Empty<IModelValidatorProvider>());

            var actionBindingContextProvider = new Mock<IActionBindingContextProvider>();
            actionBindingContextProvider.Setup(p => p.GetActionBindingContextAsync(It.IsAny<ActionContext>()))
                                        .Returns(Task.FromResult(bindingContext));

            var invoker = new ReflectedActionInvoker(actionContext,
                                                     actionDescriptor,
                                                     Mock.Of<IControllerFactory>(),
                                                     actionBindingContextProvider.Object,
                                                     Mock.Of<INestedProviderManager<FilterProviderContext>>());

            var modelStateDictionary = new ModelStateDictionary();

            // Act
            var result = await invoker.GetActionArguments(modelStateDictionary);

            // Assert
            Assert.Equal(1, result.Count);
            Assert.Equal(value, result["foo"]);
        }
Пример #7
0
        public async Task GetActionArguments_DoesNotAddActionArgumentsToModelStateDictionary_IfBinderReturnsFalse()
        {
            // Arrange
            Func<object, int> method = x => 1;
            var actionDescriptor = new ReflectedActionDescriptor
            {
                MethodInfo = method.Method,
                Parameters = new List<ParameterDescriptor>
                            {
                                new ParameterDescriptor
                                {
                                    Name = "foo",
                                    ParameterBindingInfo = new ParameterBindingInfo("foo", typeof(object))
                                }
                            }
            };
            var binder = new Mock<IModelBinder>();
            binder.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
                  .Returns(Task.FromResult(result: false));
            var actionContext = new ActionContext(new RouteContext(Mock.Of<HttpContext>()),
                                                  actionDescriptor);
            var bindingContext = new ActionBindingContext(actionContext,
                                                          Mock.Of<IModelMetadataProvider>(),
                                                          binder.Object,
                                                          Mock.Of<IValueProvider>(),
                                                          Mock.Of<IInputFormatterProvider>(),
                                                          Enumerable.Empty<IModelValidatorProvider>());

            var actionBindingContextProvider = new Mock<IActionBindingContextProvider>();
            actionBindingContextProvider.Setup(p => p.GetActionBindingContextAsync(It.IsAny<ActionContext>()))
                                        .Returns(Task.FromResult(bindingContext));

            var invoker = new ReflectedActionInvoker(actionContext,
                                                     actionDescriptor,
                                                     Mock.Of<IControllerFactory>(),
                                                     actionBindingContextProvider.Object,
                                                     Mock.Of<INestedProviderManager<FilterProviderContext>>());

            var modelStateDictionary = new ModelStateDictionary();

            // Act
            var result = await invoker.GetActionArguments(modelStateDictionary);

            // Assert
            Assert.Empty(result);
        }
Пример #8
0
        private ReflectedActionInvoker CreateInvoker(IFilter[] filters, bool actionThrows = false)
        {
            var actionDescriptor = new ReflectedActionDescriptor()
            {
                FilterDescriptors = new List<FilterDescriptor>(),
                Parameters = new List<ParameterDescriptor>(),
            };

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

            var httpContext = new Mock<HttpContext>(MockBehavior.Loose);
            var httpResponse = new Mock<HttpResponse>(MockBehavior.Loose);
            httpContext.SetupGet(c => c.Response).Returns(httpResponse.Object);
            httpResponse.SetupGet(r => r.Body).Returns(new MemoryStream());

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

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

            var actionBindingContextProvider = new Mock<IActionBindingContextProvider>(MockBehavior.Strict);
            actionBindingContextProvider
                .Setup(abcp => abcp.GetActionBindingContextAsync(It.IsAny<ActionContext>()))
                .Returns(Task.FromResult(new ActionBindingContext(null, null, null, null, null, null)));

            var filterProvider = new Mock<INestedProviderManager<FilterProviderContext>>(MockBehavior.Strict);
            filterProvider
                .Setup(fp => fp.Invoke(It.IsAny<FilterProviderContext>()))
                .Callback<FilterProviderContext>(
                    context => context.Results.AddRange(filters.Select(f => new FilterItem(null, f))));

            var invoker = new ReflectedActionInvoker(
                actionContext,
                actionDescriptor,
                controllerFactory.Object,
                actionBindingContextProvider.Object,
                filterProvider.Object);

            return invoker;
        }
        public List <ReflectedActionDescriptor> Build(ReflectedApplicationModel model)
        {
            var actions = new List <ReflectedActionDescriptor>();

            var routeGroupsByTemplate = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);
            var removalConstraints    = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

            var routeTemplateErrors = new List <string>();

            foreach (var controller in model.Controllers)
            {
                var controllerDescriptor = new ControllerDescriptor(controller.ControllerType);
                foreach (var action in controller.Actions)
                {
                    var parameterDescriptors = new List <ParameterDescriptor>();
                    foreach (var parameter in action.Parameters)
                    {
                        var isFromBody = parameter.Attributes.OfType <FromBodyAttribute>().Any();

                        parameterDescriptors.Add(new ParameterDescriptor()
                        {
                            Name       = parameter.ParameterName,
                            IsOptional = parameter.IsOptional,

                            ParameterBindingInfo = isFromBody
                                ? null
                                : new ParameterBindingInfo(
                                parameter.ParameterName,
                                parameter.ParameterInfo.ParameterType),

                            BodyParameterInfo = isFromBody
                                ? new BodyParameterInfo(parameter.ParameterInfo.ParameterType)
                                : null
                        });
                    }

                    var actionDescriptor = new ReflectedActionDescriptor()
                    {
                        Name = action.ActionName,
                        ControllerDescriptor = controllerDescriptor,
                        MethodInfo           = action.ActionMethod,
                        Parameters           = parameterDescriptors,
                        RouteConstraints     = new List <RouteDataActionConstraint>(),
                    };

                    actionDescriptor.DisplayName = string.Format(
                        "{0}.{1}",
                        action.ActionMethod.DeclaringType.FullName,
                        action.ActionMethod.Name);

                    var httpMethods = action.HttpMethods;
                    if (httpMethods != null && httpMethods.Count > 0)
                    {
                        actionDescriptor.MethodConstraints = new List <HttpMethodConstraint>()
                        {
                            new HttpMethodConstraint(httpMethods)
                        };
                    }

                    actionDescriptor.RouteConstraints.Add(new RouteDataActionConstraint(
                                                              "controller",
                                                              controller.ControllerName));

                    if (action.IsActionNameMatchRequired)
                    {
                        actionDescriptor.RouteConstraints.Add(new RouteDataActionConstraint(
                                                                  "action",
                                                                  action.ActionName));
                    }
                    else
                    {
                        actionDescriptor.RouteConstraints.Add(new RouteDataActionConstraint(
                                                                  "action",
                                                                  RouteKeyHandling.DenyKey));
                    }

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

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

                    var templateText = AttributeRouteTemplate.Combine(
                        controller.RouteTemplate,
                        action.RouteTemplate);

                    if (templateText != null)
                    {
                        // An attribute routed action will ignore conventional routed constraints. We still
                        // want to provide these values as ambient values.
                        foreach (var constraint in actionDescriptor.RouteConstraints)
                        {
                            actionDescriptor.RouteValueDefaults.Add(constraint.RouteKey, constraint.RouteValue);
                        }

                        // Replaces tokens like [controller]/[action] in the route template with the actual values
                        // for this action.
                        try
                        {
                            templateText = AttributeRouteTemplate.ReplaceTokens(
                                templateText,
                                actionDescriptor.RouteValueDefaults);
                        }
                        catch (InvalidOperationException ex)
                        {
                            var message = Resources.FormatAttributeRoute_IndividualErrorMessage(
                                actionDescriptor.DisplayName,
                                Environment.NewLine,
                                ex.Message);

                            routeTemplateErrors.Add(message);
                        }

                        actionDescriptor.AttributeRouteTemplate = templateText;

                        // An attribute routed action is matched by its 'route group' which identifies all equivalent
                        // actions.
                        string routeGroup;
                        if (!routeGroupsByTemplate.TryGetValue(templateText, out routeGroup))
                        {
                            routeGroup = GetRouteGroup(templateText);
                            routeGroupsByTemplate.Add(templateText, routeGroup);
                        }

                        var routeConstraints = new List <RouteDataActionConstraint>();
                        routeConstraints.Add(new RouteDataActionConstraint(
                                                 AttributeRouting.RouteGroupKey,
                                                 routeGroup));

                        actionDescriptor.RouteConstraints = routeConstraints;
                    }

                    actionDescriptor.FilterDescriptors =
                        action.Filters.Select(f => new FilterDescriptor(f, FilterScope.Action))
                        .Concat(controller.Filters.Select(f => new FilterDescriptor(f, FilterScope.Controller)))
                        .Concat(model.Filters.Select(f => new FilterDescriptor(f, FilterScope.Global)))
                        .OrderBy(d => d, FilterDescriptorOrderComparer.Comparer)
                        .ToList();

                    actions.Add(actionDescriptor);
                }
            }

            foreach (var actionDescriptor in actions)
            {
                foreach (var key in removalConstraints)
                {
                    if (actionDescriptor.AttributeRouteTemplate == null)
                    {
                        // Any any attribute routes are in use, then non-attribute-routed ADs can't be selected
                        // when a route group returned by the route.
                        if (routeGroupsByTemplate.Any())
                        {
                            actionDescriptor.RouteConstraints.Add(new RouteDataActionConstraint(
                                                                      AttributeRouting.RouteGroupKey,
                                                                      RouteKeyHandling.DenyKey));
                        }

                        if (!HasConstraint(actionDescriptor.RouteConstraints, key))
                        {
                            actionDescriptor.RouteConstraints.Add(new RouteDataActionConstraint(
                                                                      key,
                                                                      RouteKeyHandling.DenyKey));
                        }
                    }
                    else
                    {
                        // We still want to add a 'null' for any constraint with DenyKey so that link generation
                        // works properly.
                        //
                        // Consider an action like { area = "", controller = "Home", action = "Index" }. Even if
                        // it's attribute routed, it needs to know that area must be null to generate a link.
                        if (!actionDescriptor.RouteValueDefaults.ContainsKey(key))
                        {
                            actionDescriptor.RouteValueDefaults.Add(key, null);
                        }
                    }
                }
            }

            if (routeTemplateErrors.Any())
            {
                var message = Resources.FormatAttributeRoute_AggregateErrorMessage(
                    Environment.NewLine,
                    string.Join(Environment.NewLine + Environment.NewLine, routeTemplateErrors));
                throw new InvalidOperationException(message);
            }

            return(actions);
        }
Пример #10
0
        private void ValidateActionGroupConfiguration(
            IDictionary <MethodInfo, IDictionary <ReflectedActionModel, IList <ReflectedActionDescriptor> > > methodMap,
            ReflectedActionDescriptor actionDescriptor,
            IDictionary <MethodInfo, string> routingConfigurationErrors)
        {
            string combinedErrorMessage = null;

            var hasAttributeRoutedActions      = false;
            var hasConventionallyRoutedActions = false;

            var invalidHttpMethodActions = new Dictionary <ReflectedActionModel, IEnumerable <string> >();

            var actionsForMethod = methodMap[actionDescriptor.MethodInfo];

            foreach (var reflectedAction in actionsForMethod)
            {
                foreach (var action in reflectedAction.Value)
                {
                    if (IsAttributeRoutedAction(action))
                    {
                        hasAttributeRoutedActions = true;
                    }
                    else
                    {
                        hasConventionallyRoutedActions = true;
                    }
                }

                // Keep a list of actions with possible invalid IHttpActionMethodProvider attributes
                // to generate an error in case the method generates attribute routed actions.
                ValidateActionHttpMethodProviders(reflectedAction.Key, invalidHttpMethodActions);
            }

            // Validate that no method result in attribute and non attribute actions at the same time.
            // By design, mixing attribute and conventionally actions in the same method is not allowed.
            // This is for example the case when someone uses[HttpGet("Products")] and[HttpPost]
            // on the same  method.
            if (hasAttributeRoutedActions && hasConventionallyRoutedActions)
            {
                combinedErrorMessage = CreateMixedRoutedActionDescriptorsErrorMessage(
                    actionDescriptor,
                    actionsForMethod);
            }

            // Validate that no method that creates attribute routed actions and
            // also uses attributes that only constrain the set of HTTP methods. For example,
            // if an attribute that implements IActionHttpMethodProvider but does not implement
            // IRouteTemplateProvider is used with an attribute that implements IRouteTemplateProvider on
            // the same action, the HTTP methods provided by the attribute that only implements
            // IActionHttpMethodProvider would be silently ignored, so we choose to throw to
            // inform the user of the invalid configuration.
            if (hasAttributeRoutedActions && invalidHttpMethodActions.Any())
            {
                var errorMessage = CreateInvalidActionHttpMethodProviderErrorMessage(
                    actionDescriptor,
                    invalidHttpMethodActions,
                    actionsForMethod);

                combinedErrorMessage = CombineErrorMessage(combinedErrorMessage, errorMessage);
            }

            if (combinedErrorMessage != null)
            {
                routingConfigurationErrors.Add(actionDescriptor.MethodInfo, combinedErrorMessage);
            }
        }
Пример #11
0
 private static bool IsAttributeRoutedAction(ReflectedActionDescriptor actionDescriptor)
 {
     return(actionDescriptor.AttributeRouteInfo != null &&
            actionDescriptor.AttributeRouteInfo.Template != null);
 }