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)); }
private static ActionConstraintContext CreateActionConstraintContext(HttpMethodActionConstraint constraint) { var context = new ActionConstraintContext(); var actionSelectorCandidate = new ActionSelectorCandidate(new ActionDescriptor(), new List<IActionConstraint> { constraint }); context.Candidates = new List<ActionSelectorCandidate> { actionSelectorCandidate }; context.CurrentCandidate = context.Candidates[0]; return context; }
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; } }
public bool Accept(ActionConstraintContext context) { bool result = false; var contentType = context.RouteContext.HttpContext.Request.ContentType; if (contentType != null) { string[] parts = contentType.Split('+'); if (parts.Length == 2) { if (_contentTypeBase.Equals(parts[0], StringComparison.OrdinalIgnoreCase)) result = true; } } return result; }
private IReadOnlyList<ActionSelectorCandidate> EvaluateActionConstraintsCore( 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; // Perf: Avoid allocations for (var i = 0; i < candidates.Count; i++) { var candidate = candidates[i]; if (candidate.Constraints != null) { for (var j = 0; j < candidate.Constraints.Count; j++) { var constraint = candidate.Constraints[j]; 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; // Perf: Avoid allocations for (var i = 0; i < candidates.Count; i++) { var candidate = candidates[i]; var isMatch = true; var foundMatchingConstraint = false; if (candidate.Constraints != null) { constraintContext.CurrentCandidate = candidate; for (var j = 0; j < candidate.Constraints.Count; j++) { var constraint = candidate.Constraints[j]; if (constraint.Order == order) { foundMatchingConstraint = true; if (!constraint.Accept(constraintContext)) { isMatch = false; _logger.ConstraintMismatch( candidate.Action.DisplayName, candidate.Action.Id, constraint); 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 = EvaluateActionConstraintsCore(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 EvaluateActionConstraintsCore(context, actionsWithoutConstraint, order); } }
/// <inheritdoc /> public bool Accept(ActionConstraintContext context) { return(IsValidForRequest(context.RouteContext, context.CurrentCandidate.Action)); }
public bool Accept(ActionConstraintContext context) { return Pass; }
public void Accept_AcceptsActionWithSatisfiedParameters() { // Arrange var action = new ActionDescriptor(); action.Parameters = new List<ParameterDescriptor>() { new ParameterDescriptor() { BindingInfo = new BindingInfo() { BindingSource = (new FromUriAttribute()).BindingSource, }, Name = "id", ParameterType = typeof(int), }, new ParameterDescriptor() { BindingInfo = new BindingInfo() { BindingSource = (new FromUriAttribute()).BindingSource, }, Name = "quantity", ParameterType = typeof(int), }, }; var constraint = new OverloadActionConstraint(); var context = new ActionConstraintContext(); context.Candidates = new List<ActionSelectorCandidate>() { new ActionSelectorCandidate(action, new [] { constraint }), }; context.CurrentCandidate = context.Candidates[0]; context.RouteContext = CreateRouteContext("?quantity=5", new { id = 17 }); // Act & Assert Assert.True(constraint.Accept(context)); }
public void Accept_RejectsWorseMatch_OptionalParameter() { // Arrange var action1 = new ActionDescriptor(); action1.Parameters = new List<ParameterDescriptor>() { new ParameterDescriptor() { BindingInfo = new BindingInfo() { BindingSource = (new FromUriAttribute()).BindingSource, }, Name = "id", ParameterType = typeof(int), }, new ParameterDescriptor() { BindingInfo = new BindingInfo() { BindingSource = (new FromUriAttribute()).BindingSource, }, Name = "quantity", ParameterType = typeof(int), }, }; var optionalParameters = new HashSet<string>(); optionalParameters.Add("quantity"); action1.Properties.Add("OptionalParameters", optionalParameters); var action2 = new ActionDescriptor(); action2.Parameters = new List<ParameterDescriptor>() { new ParameterDescriptor() { BindingInfo = new BindingInfo() { BindingSource = (new FromUriAttribute()).BindingSource, }, Name = "id", ParameterType = typeof(int), }, new ParameterDescriptor() { BindingInfo = new BindingInfo() { BindingSource = (new FromUriAttribute()).BindingSource, }, Name = "quantity", ParameterType = typeof(int), }, }; var constraint = new OverloadActionConstraint(); var context = new ActionConstraintContext(); context.Candidates = new List<ActionSelectorCandidate>() { new ActionSelectorCandidate(action1, new [] { constraint }), new ActionSelectorCandidate(action2, new [] { constraint }), }; context.CurrentCandidate = context.Candidates[0]; context.RouteContext = CreateRouteContext("?quantity=5", new { id = 17 }); // Act & Assert Assert.False(constraint.Accept(context)); }
public void Accept_RejectsActionMatchWithMissingParameter() { // Arrange var action = new ActionDescriptor(); action.Parameters = new List<ParameterDescriptor>() { new ParameterDescriptor() { BindingInfo = new BindingInfo() { BindingSource = (new FromUriAttribute()).BindingSource, }, Name = "id", ParameterType = typeof(int), }, }; var constraint = new OverloadActionConstraint(); var context = new ActionConstraintContext(); context.Candidates = new List<ActionSelectorCandidate>() { new ActionSelectorCandidate(action, new [] { constraint }), }; context.CurrentCandidate = context.Candidates[0]; context.RouteContext = CreateRouteContext(); // Act & Assert Assert.False(constraint.Accept(context)); }
public bool Accept(ActionConstraintContext context) { return _requestId == _requestIdService.RequestId; }
/// <inheritdoc /> 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; } var requestContentType = context.RouteContext.HttpContext.Request.ContentType; // 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; } // Confirm the request's content type is more specific than (a media type this action supports e.g. OK // if client sent "text/plain" data and this action supports "text/*". if (IsSubsetOfAnyContentType(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; }
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 bool Accept(ActionConstraintContext context) { throw new NotImplementedException(); }
/// <inheritdoc /> public bool Accept(ActionConstraintContext context) { return IsValidForRequest(context.RouteContext, context.CurrentCandidate.Action); }