1

I have written a custom route but found that its called for Action methods which have not specified the constraints in the attribute routing.

[RoutePrefix("api/v1/Orders")]
public class OrdersController : BaseController
{

    [Route("{orderId}/archive")]   
    public HttpResponseMessage Put(Guid orderId, [FromBody]List<ComplexObject> c)
    {

    }        

    public HttpResponseMessage Get([FromUri]ComplexObject c)
    {

    }        

[Route("{orderId:checkGuid(orderId,BadRequest)}/{personId:checkGuid(personId,BadRequest)}")]
    public HttpResponseMessage Get(Guid orderId, Guid personId)
    {

    }
}

public class CheckGuidRouteConstraint : IHttpRouteConstraint
{       
    private readonly HttpStatusCode _statusCode;
    private readonly string _parameterName;

    private HttpStatusCode _default = HttpStatusCode.BadRequest;

    public CheckGuidRouteConstraint(string parameterName,string statusCode)
    {
        if (!Enum.TryParse(statusCode, true, out _statusCode))
        {
            _statusCode = _default;
        }
        _parameterName = parameterName;
    }

    public bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName, IDictionary<string, object> values, HttpRouteDirection routeDirection)
    {
        bool isRouteWrong = doSomeCheck();

        if(isRouteWrong)
        {                
            //throw custom exception with proper message
        }

        return true;
    }
}

And added it in

var constraintResolver = new DefaultInlineConstraintResolver();
        constraintResolver.ConstraintMap.Add("checkGuid", typeof(CheckGuidRouteConstraint));
        config.MapHttpAttributeRoutes(constraintResolver);

Now when I access the Put() method, the route constaraint's Match() method is called more than 1 times and finally fails. Please note that I haven't mentioned any route constraint in my Put() attribute route.

thinkmmk
  • 487
  • 1
  • 8
  • 22

1 Answers1

0

This way does not work if you have many custom IHttpRouteConstraint and controller with same methods. Seems WebAPI not parsing route parameters and just trying all of them before any of registered IHttpRouteConstraint return true. So, if one of them throwing exception it automatically stopping processing other constraints. If bad constrain was registered first you will get error response even this constraint not used in route template.

 [HttpGet]
    [Route("{code:enum(System.Net.HttpStatusCode)}")]
    public IHttpActionResult Enum(string code)
    {
        return Ok();
    }

    [HttpGet]
    [Route("{period:values(days|weeks|months)}")]
    public IHttpActionResult Value(string period)
    {
        return Ok();
    }

for example if 'enum' constraint has similar implementation same as yours and registered first

 constraintsResolver.ConstraintMap.Add("enum", typeof(EnumConstraint));
 constraintsResolver.ConstraintMap.Add("values", typeof(ValuesConstraint));
 config.MapHttpAttributeRoutes(constraintsResolver);

Value action will never return Ok.

h0use
  • 81
  • 1
  • 4