Routing in MVC 6

后端 未结 1 1760
暖寄归人
暖寄归人 2021-01-13 17:40

I have a super simple controller with 2 methods:

public IActionResult Users(long id)
{
    return Json(new { name = \"Example User\" });
}

public IActionRes         


        
相关标签:
1条回答
  • 2021-01-13 18:29

    In your original webapi code, you were using Routes.MapHttpRoute which adds webapi specific routes. This is different from an MVC route which won´t take into account the parameters in the action, for instance you would have the same problem in MVC 5 if you were using Routes.MapRoute.

    The same thing is happening in your MVC 6 code, since you are adding a standard MVC route using routes.MapRoute. In both cases the framework is finding 2 controller actions matching the same route with no additional constraints. It needs some help in order to select one of those 2 actions.

    The easiest way to disambiguate the api actions would be using attribute routing instead of defining a route, as in this example:

    [Route("v1/[controller]")]
    public class UsersController : Controller
    {
        [HttpGet("{id:int}")]
        public IActionResult Users(long id)
        {
            return Json(new { name = "Example User" });
        }
    
        public IActionResult Users()
        {
            return Json(new { list = new[] { "a", "b" } });
        }
    }
    

    There are other options that would let you change the behaviour of the MVC routing in MVC 6. You could create your own IActionConstraint attribute to enforce having or not a given parameter. That way one of those actions requires an id parameter in the route while the other requires not to have an id parameter (Warning, untested code):

    public class UsersController : Controller
    {
        [RouteParameterConstraint("id", ShouldAppear=true)]
        public IActionResult Users(long id)
        {
            return Json(new { name = "Example User" });
        }
    
        [RouteParameterConstraint("id", ShouldNotAppear=true)]
        public IActionResult Users()
        {
            return Json(new { list = new[] { "a", "b" } });
        }
    }
    
    public class RouteParameterConstraintAttribute : Attribute, IActionConstraint
    {
        private routeParameterName;
    
        public RouteParameterConstraintAttribute(string routeParameterName)
        {
            this.routerParamterName = routerParameterName;
        }
    
        public int Order => 0;
        public bool ShouldAppear {get; set;}
        public bool ShouldNotAppear {get; set;}
    
        public bool Accept(ActionConstraintContext context)
        {
            if(ShouldAppear) return context.RouteContext.RouteData.Values["country"] != null;
            if(ShouldNotAppear) return context.RouteContext.RouteData.Values["country"] == null;
    
            return true;
        }
    }
    

    A better option to deal with webapi 2 style controllers would be adding conventions into the MVC pipeline. This is exactly what the Microsoft.AspNet.Mvc.WebApiCompatShim is doing to help migrating webapi 2 controllers. You can see the conventions added here. Check this guide for a quick overview of this package.

    0 讨论(0)
提交回复
热议问题