在MVC 6中进行路由 [英] Routing in MVC 6

查看:70
本文介绍了在MVC 6中进行路由的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有2种方法的超级简单控制器:

I have a super simple controller with 2 methods:

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

public IActionResult Users()
{
    return Json(new { list = new List<User>() });
}

一个选择所有用户,另一个选择返回所有用户.在Web API 2中,我可以使用以下路由,并且一切正常:

One to select all users and the other to return all users. In web api 2 I could user the following route and everything worked fine:

config.Routes.MapHttpRoute(
                name: "Users",
                routeTemplate: "v1/Users",
                defaults: new { action = "Users", controller = "Users" },
                constraints: null,
                handler: new TokenValidationHandler() { InnerHandler = new HttpControllerDispatcher(config) }
            );

我在startup.cs中设置了以下路由:

I have the following routes setup in startup.cs:

app.UseMvc(routes =>
            {
                routes.MapRoute(name: "User_Default", template: "v1/{controller=Users}/{action=Users}/{id?}");
            });

但是这给了我AmbiguousActionException: Multiple actions matched. The following actions matched route data and had all constraints satisfied

我在做什么错了?

推荐答案

在您原始的webapi代码中,您使用的是Routes.MapHttpRoute,它添加了webapi特定的路由.这与MVC路由不同,后者不会考虑操作中的参数,例如,如果您使用Routes.MapRoute,则在MVC 5中也会遇到相同的问题.

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.

由于要使用routes.MapRoute添加标准MVC路由,因此MVC 6代码中也发生了同样的情况.在这两种情况下,框架都会找到2个与同一路由匹配的控制器动作,而没有其他约束.需要一些帮助才能选择这两个动作之一.

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.

消除api操作歧义的最简单方法是使用属性路由而不是定义路由,如

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" } });
    }
}

还有其他选项可以让您更改MVC 6中MVC路由的行为.您可以创建自己的IActionConstraint属性以强制具有或不具有给定参数.这样,其中一个操作就需要在路由中使用id参数,而其他操作则不需要具有id参数(警告,未经测试的代码):

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;
    }
}

处理webapi 2样式控制器的更好选择是将约定添加到MVC管道中.这正是Microsoft.AspNet.Mvc.WebApiCompatShim为帮助迁移webapi 2控制器所做的工作.您可以在此处.检查

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.

这篇关于在MVC 6中进行路由的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆