public bool Accept(ActionConstraintContext context)
 {
     int version;
     if (int.TryParse(GetVersion(context.RouteContext.HttpContext.Request), out version))
     {
         return (_minVersion == null || _minVersion <= version) &&
             (_maxVersion == null || _maxVersion >= version);
     }
     else
     {
         return false;
     }
 }
Exemple #2
0
        public void Accept_ForNoRequestType_ReturnsTrueForAllConstraints(string contentType)
        {
            // Arrange
            var constraint1          = new ConsumesAttribute("application/json");
            var actionWithConstraint = new ActionDescriptor()
            {
                FilterDescriptors =
                    new List <FilterDescriptor>()
                {
                    new FilterDescriptor(constraint1, FilterScope.Action)
                }
            };

            var constraint2           = new ConsumesAttribute("text/xml");
            var actionWithConstraint2 = new ActionDescriptor()
            {
                FilterDescriptors =
                    new List <FilterDescriptor>()
                {
                    new FilterDescriptor(constraint2, FilterScope.Action)
                }
            };

            var actionWithoutConstraint = new ActionDescriptor();

            var context = new ActionConstraintContext();

            context.Candidates = new List <ActionSelectorCandidate>()
            {
                new ActionSelectorCandidate(actionWithConstraint, new [] { constraint1 }),
                new ActionSelectorCandidate(actionWithConstraint2, new [] { constraint2 }),
            };

            context.RouteContext = CreateRouteContext(contentType: contentType);

            // Act & Assert
            context.CurrentCandidate = context.Candidates[0];
            Assert.True(constraint1.Accept(context));
            context.CurrentCandidate = context.Candidates[1];
            Assert.True(constraint2.Accept(context));
        }
Exemple #3
0
        public void Accept_ForNoMatchingCandidates_SelectsTheFirstCandidate(string contentType)
        {
            // Arrange
            var constraint1 = new ConsumesAttribute("application/json", "text/xml");
            var action1     = new ActionDescriptor()
            {
                FilterDescriptors =
                    new List <FilterDescriptor>()
                {
                    new FilterDescriptor(constraint1, FilterScope.Action)
                }
            };

            var constraint2 = new Mock <ITestConsumeConstraint>();
            var action2     = new ActionDescriptor()
            {
                FilterDescriptors =
                    new List <FilterDescriptor>()
                {
                    new FilterDescriptor(constraint2.Object, FilterScope.Action)
                }
            };

            constraint2.Setup(o => o.Accept(It.IsAny <ActionConstraintContext>()))
            .Returns(false);

            var context = new ActionConstraintContext();

            context.Candidates = new List <ActionSelectorCandidate>()
            {
                new ActionSelectorCandidate(action1, new [] { constraint1 }),
                new ActionSelectorCandidate(action2, new [] { constraint2.Object }),
            };

            context.CurrentCandidate = context.Candidates[0];
            context.RouteContext     = CreateRouteContext(contentType: contentType);

            // Act & Assert
            Assert.True(constraint1.Accept(context));
        }
        public void Accept_MatchesForMachingRequestContentType(string contentType)
        {
            // Arrange
            var constraint = new ConsumesAttribute("application/json", "text/xml");
            var action = new ActionDescriptor()
            {
                FilterDescriptors =
                    new List<FilterDescriptor>() { new FilterDescriptor(constraint, FilterScope.Action) }
            };

            var context = new ActionConstraintContext();
            context.Candidates = new List<ActionSelectorCandidate>()
            {
                new ActionSelectorCandidate(action, new [] { constraint }),
            };

            context.CurrentCandidate = context.Candidates[0];
            context.RouteContext = CreateRouteContext(contentType: contentType);

            // Act & Assert
            Assert.True(constraint.Accept(context));
        }
Exemple #5
0
 public bool Accept([NotNull] ActionConstraintContext context)
 {
     return(Pass);
 }
Exemple #6
0
        public bool Accept(ActionConstraintContext context)
        {
            // If this constraint is not closest to the action, it will be skipped.
            if (!IsApplicable(context.CurrentCandidate.Action))
            {
                // Since the constraint is to be skipped, returning true here
                // will let the current candidate ignore this constraint and will
                // be selected based on other constraints for this action.
                return(true);
            }

            MediaTypeHeaderValue requestContentType = null;

            MediaTypeHeaderValue.TryParse(context.RouteContext.HttpContext.Request.ContentType, out requestContentType);

            // If the request content type is null we need to act like pass through.
            // In case there is a single candidate with a constraint it should be selected.
            // If there are multiple actions with consumes action constraints this should result in ambiguous exception
            // unless there is another action without a consumes constraint.
            if (requestContentType == null)
            {
                var isActionWithoutConsumeConstraintPresent = context.Candidates.Any(
                    candidate => candidate.Constraints == null ||
                    !candidate.Constraints.Any(constraint => constraint is IConsumesActionConstraint));

                return(!isActionWithoutConsumeConstraintPresent);
            }

            if (ContentTypes.Any(c => c.IsSubsetOf(requestContentType)))
            {
                return(true);
            }

            var firstCandidate = context.Candidates[0];

            if (firstCandidate != context.CurrentCandidate)
            {
                // If the current candidate is not same as the first candidate,
                // we need not probe other candidates to see if they apply.
                // Only the first candidate is allowed to probe other candidates and based on the result select itself.
                return(false);
            }

            // Run the matching logic for all IConsumesActionConstraints we can find, and see what matches.
            // 1). If we have a unique best match, then only that constraint should return true.
            // 2). If we have multiple matches, then all constraints that match will return true
            // , resulting in ambiguity(maybe).
            // 3). If we have no matches, then we choose the first constraint to return true.It will later return a 415
            foreach (var candidate in context.Candidates)
            {
                if (candidate == firstCandidate)
                {
                    continue;
                }

                var tempContext = new ActionConstraintContext()
                {
                    Candidates       = context.Candidates,
                    RouteContext     = context.RouteContext,
                    CurrentCandidate = candidate
                };

                if (candidate.Constraints == null || candidate.Constraints.Count == 0 ||
                    candidate.Constraints.Any(constraint => constraint is IConsumesActionConstraint &&
                                              constraint.Accept(tempContext)))
                {
                    // There is someone later in the chain which can handle the request.
                    // end the process here.
                    return(false);
                }
            }

            // There is no one later in the chain that can handle this content type return a false positive so that
            // later we can detect and return a 415.
            return(true);
        }
 /// <inheritdoc />
 public bool Accept(ActionConstraintContext context)
 {
     return(IsValidForRequest(context.RouteContext, context.CurrentCandidate.Action));
 }
        public bool Accept(ActionConstraintContext context)
        {
            // If this constraint is not closest to the action, it will be skipped.
            if (!IsApplicable(context.CurrentCandidate.Action))
            {
                // Since the constraint is to be skipped, returning true here
                // will let the current candidate ignore this constraint and will
                // be selected based on other constraints for this action.
                return true;
            }

            MediaTypeHeaderValue requestContentType = null;
            MediaTypeHeaderValue.TryParse(context.RouteContext.HttpContext.Request.ContentType, out requestContentType);

            // If the request content type is null we need to act like pass through.
            // In case there is a single candidate with a constraint it should be selected.
            // If there are multiple actions with consumes action constraints this should result in ambiguous exception
            // unless there is another action without a consumes constraint.
            if (requestContentType == null)
            {
                var isActionWithoutConsumeConstraintPresent = context.Candidates.Any(
                    candidate => candidate.Constraints == null ||
                    !candidate.Constraints.Any(constraint => constraint is IConsumesActionConstraint));

                return !isActionWithoutConsumeConstraintPresent;
            }

            if (ContentTypes.Any(c => c.IsSubsetOf(requestContentType)))
            {
                return true;
            }

            var firstCandidate = context.Candidates[0];
            if (firstCandidate != context.CurrentCandidate)
            {
                // If the current candidate is not same as the first candidate,
                // we need not probe other candidates to see if they apply.
                // Only the first candidate is allowed to probe other candidates and based on the result select itself.
                return false;
            }

            // Run the matching logic for all IConsumesActionConstraints we can find, and see what matches.
            // 1). If we have a unique best match, then only that constraint should return true.
            // 2). If we have multiple matches, then all constraints that match will return true
            // , resulting in ambiguity(maybe).
            // 3). If we have no matches, then we choose the first constraint to return true.It will later return a 415
            foreach (var candidate in context.Candidates)
            {
                if (candidate == firstCandidate)
                {
                    continue;
                }

                var tempContext = new ActionConstraintContext()
                {
                    Candidates = context.Candidates,
                    RouteContext = context.RouteContext,
                    CurrentCandidate = candidate
                };

                if (candidate.Constraints == null || candidate.Constraints.Count == 0 ||
                    candidate.Constraints.Any(constraint => constraint is IConsumesActionConstraint &&
                                                            constraint.Accept(tempContext)))
                {
                    // There is someone later in the chain which can handle the request.
                    // end the process here.
                    return false;
                }
            }

            // There is no one later in the chain that can handle this content type return a false positive so that
            // later we can detect and return a 415.
            return true;
        }
Exemple #9
0
        private IReadOnlyList <ActionSelectorCandidate> EvaluateActionConstraints(
            RouteContext context,
            IReadOnlyList <ActionSelectorCandidate> candidates,
            int?startingOrder)
        {
            // Find the next group of constraints to process. This will be the lowest value of
            // order that is higher than startingOrder.
            int?order = null;

            foreach (var candidate in candidates)
            {
                if (candidate.Constraints != null)
                {
                    foreach (var constraint in candidate.Constraints)
                    {
                        if ((startingOrder == null || constraint.Order > startingOrder) &&
                            (order == null || constraint.Order < order))
                        {
                            order = constraint.Order;
                        }
                    }
                }
            }

            // If we don't find a 'next' then there's nothing left to do.
            if (order == null)
            {
                return(candidates);
            }

            // Since we have a constraint to process, bisect the set of actions into those with and without a
            // constraint for the 'current order'.
            var actionsWithConstraint    = new List <ActionSelectorCandidate>();
            var actionsWithoutConstraint = new List <ActionSelectorCandidate>();

            var constraintContext = new ActionConstraintContext();

            constraintContext.Candidates   = candidates;
            constraintContext.RouteContext = context;

            foreach (var candidate in candidates)
            {
                var isMatch = true;
                var foundMatchingConstraint = false;

                if (candidate.Constraints != null)
                {
                    constraintContext.CurrentCandidate = candidate;
                    foreach (var constraint in candidate.Constraints)
                    {
                        if (constraint.Order == order)
                        {
                            foundMatchingConstraint = true;

                            if (!constraint.Accept(constraintContext))
                            {
                                isMatch = false;
                                break;
                            }
                        }
                    }
                }

                if (isMatch && foundMatchingConstraint)
                {
                    actionsWithConstraint.Add(candidate);
                }
                else if (isMatch)
                {
                    actionsWithoutConstraint.Add(candidate);
                }
            }

            // If we have matches with constraints, those are 'better' so try to keep processing those
            if (actionsWithConstraint.Count > 0)
            {
                var matches = EvaluateActionConstraints(context, actionsWithConstraint, order);
                if (matches?.Count > 0)
                {
                    return(matches);
                }
            }

            // If the set of matches with constraints can't work, then process the set without constraints.
            if (actionsWithoutConstraint.Count == 0)
            {
                return(null);
            }
            else
            {
                return(EvaluateActionConstraints(context, actionsWithoutConstraint, order));
            }
        }
 /// <inheritdoc />
 public bool Accept(ActionConstraintContext context)
 {
     return IsValidForRequest(context.RouteContext, context.CurrentCandidate.Action);
 }
        public void Accept_MatchesForMachingRequestContentType(string contentType)
        {
            // Arrange
            var constraint = new ConsumesAttribute("application/json", "text/xml");
            var action = new ActionDescriptor()
            {
                FilterDescriptors =
                    new List<FilterDescriptor>() { new FilterDescriptor(constraint, FilterScope.Action) }
            };

            var context = new ActionConstraintContext();
            context.Candidates = new List<ActionSelectorCandidate>()
            {
                new ActionSelectorCandidate(action, new [] { constraint }),
            };

            context.CurrentCandidate = context.Candidates[0];
            context.RouteContext = CreateRouteContext(contentType: contentType);

            // Act & Assert
            Assert.True(constraint.Accept(context));
        }
        public void Accept_ForNoRequestType_ReturnsTrueForAllConstraints(string contentType)
        {
            // Arrange
            var constraint1 = new ConsumesAttribute("application/json");
            var actionWithConstraint = new ActionDescriptor()
            {
                FilterDescriptors =
                    new List<FilterDescriptor>() { new FilterDescriptor(constraint1, FilterScope.Action) }
            };

            var constraint2 = new ConsumesAttribute("text/xml");
            var actionWithConstraint2 = new ActionDescriptor()
            {
                FilterDescriptors =
                    new List<FilterDescriptor>() { new FilterDescriptor(constraint2, FilterScope.Action) }
            };

            var actionWithoutConstraint = new ActionDescriptor();

            var context = new ActionConstraintContext();
            context.Candidates = new List<ActionSelectorCandidate>()
            {
                new ActionSelectorCandidate(actionWithConstraint, new [] { constraint1 }),
                new ActionSelectorCandidate(actionWithConstraint2, new [] { constraint2 }),
            };

            context.RouteContext = CreateRouteContext(contentType: contentType);

            // Act & Assert
            context.CurrentCandidate = context.Candidates[0];
            Assert.True(constraint1.Accept(context));
            context.CurrentCandidate = context.Candidates[1];
            Assert.True(constraint2.Accept(context));
        }
        public void Accept_UnrecognizedMediaType_SelectsTheCandidateWithoutConstraintIfPresent(string contentType)
        {
            // Arrange
            var actionWithoutConstraint = new ActionDescriptor();
            var constraint1 = new ConsumesAttribute("application/json");
            var actionWithConstraint = new ActionDescriptor()
            {
                FilterDescriptors =
                    new List<FilterDescriptor>() { new FilterDescriptor(constraint1, FilterScope.Action) }
            };

            var constraint2 = new ConsumesAttribute("text/xml");
            var actionWithConstraint2 = new ActionDescriptor()
            {
                FilterDescriptors =
                    new List<FilterDescriptor>() { new FilterDescriptor(constraint2, FilterScope.Action) }
            };

            var context = new ActionConstraintContext();
            context.Candidates = new List<ActionSelectorCandidate>()
            {
                new ActionSelectorCandidate(actionWithConstraint, new [] { constraint1 }),
                new ActionSelectorCandidate(actionWithConstraint2, new [] { constraint2 }),
                new ActionSelectorCandidate(actionWithoutConstraint, new List<IActionConstraint>()),
            };

            context.RouteContext = CreateRouteContext(contentType: contentType);

            // Act & Assert
            context.CurrentCandidate = context.Candidates[0];
            Assert.False(constraint1.Accept(context));

            context.CurrentCandidate = context.Candidates[1];
            Assert.False(constraint2.Accept(context));
        }
        public void Accept_ForNoMatchingCandidates_SelectsTheFirstCandidate(string contentType)
        {
            // Arrange
            var constraint1 = new ConsumesAttribute("application/json", "text/xml");
            var action1 = new ActionDescriptor()
            {
                FilterDescriptors =
                    new List<FilterDescriptor>() { new FilterDescriptor(constraint1, FilterScope.Action) }
            };

            var constraint2 = new Mock<ITestConsumeConstraint>();
            var action2 = new ActionDescriptor()
            {
                FilterDescriptors =
                    new List<FilterDescriptor>() { new FilterDescriptor(constraint2.Object, FilterScope.Action) }
            };

            constraint2.Setup(o => o.Accept(It.IsAny<ActionConstraintContext>()))
                       .Returns(false);

            var context = new ActionConstraintContext();
            context.Candidates = new List<ActionSelectorCandidate>()
            {
                new ActionSelectorCandidate(action1, new [] { constraint1 }),
                new ActionSelectorCandidate(action2, new [] { constraint2.Object }),
            };

            context.CurrentCandidate = context.Candidates[0];
            context.RouteContext = CreateRouteContext(contentType: contentType);

            // Act & Assert
            Assert.True(constraint1.Accept(context));
        }