【问题标题】:Routing - WebAPI and MVC in one project路由 - 一个项目中的 WebAPI 和 MVC
【发布时间】:2019-10-17 06:35:36
【问题描述】:

我有 2 个控制器。两者都处理 Bar(Foo 的孩子)。

其中一个是用于返回视图的 MVC。

[Route("Foo/Bar")]
public class FooBarController : ControllerBase
{
    public IActionResult Index()
    {
        // ...
    }

    public IActionResult SomeAction()
    {
        // ...
    }
}

其中一个用于 API,它存在于“api”的文件夹下。

[Route("api/Foo/Bar")]
[ApiController]
public class FooBarAPIController : ControllerBase
{
    //
}

无需在 FooBarController 类中添加以下行,我就可以访问 API 控制器(例如:/api/foo/bar/{id})和 MVC 控制器(例如:/FooBar/SomeAction)

[Route("Foo/Bar")]

但是当我这样做时,路由会变得混乱,并且尝试访问 /Foo/Bar/SomeAction 时出现以下错误

AmbiguousMatchException:请求匹配多个端点。匹配:

Controllers.MVC.FooBarController.Index

Controllers.MVC.FooBarController.SomeAction

【问题讨论】:

    标签: asp.net-mvc asp.net-web-api asp.net-core asp.net-mvc-routing


    【解决方案1】:

    当您没有应用该属性时,FooBarController 使用常规路由,您可能已经默认使用了。它通常将 Index 作为默认操作,并允许您还指定操作名称,因此一切正常。

    当您应用属性时,此控制器中的所有操作现在都使用属性路由。这两种路由类型没有组合,您只能使用其中一种。请注意,

    "使用属性路由控制器名称和动作名称播放不 选择动作的角色。”

    (docs source)。因此这两个动作变得相同,它们的名称被忽略,并且无法弄清楚该使用哪一个。所以你需要帮助它:

    [Route("Foo/Bar")]
    public class FooBarController : ControllerBase
    {
        [Route("")]      // To make it default for "Foo/Bar"
        [Route("Index")] // Combines to define the route template "Foo/Bar/Index"
        public IActionResult Index()
        {
            // ...
        }
    
        [Route("SomeAction")] // Combines to define the route template "Foo/Bar/SomeAction"
        public IActionResult SomeAction()
        {
            // ...
        }
    }
    

    是的,它更冗长。来自同一来源:

    属性路由需要更多的输入来指定路由;这 传统的默认路由更简洁地处理路由。然而, 属性路由允许(并且要求)精确控制哪条路由 模板适用于每个操作。

    【讨论】:

    • 啊,谢谢。我认为是这种情况,但我不想将属性路由与 MVC 控制器(只是 API 控制器)一起使用。是否有一个属性可以更改控制器路由(而不是将其更改为属性路由),我可以将其应用于控制器(而不是 startup.cs)?
    • @Beakie I don't want to use Attribute Routing with the MVC 是什么意思?正如您的描述,它可以在没有[Route("Foo/Bar")] 的情况下工作。
    【解决方案2】:

    对于您的 API 控制器,我建议将 Route 更改为 RoutePrefix["api"],这样您的所有 api 方法都将只包含路由(希望与您的主控制器的名称不同。

    [RoutePrefix("api")]
    public class MyApiController : ApiController 
    {
        [HttpGet, Route("foo/bar")]
        public IHttpActionResult GetSomething()
        {
            //do something when routing to /api/foo/bar
        }
    
        [HttpPost, Route("foobar/foobar")]
        public IHttpActionResult GetSomething()
        {
            //do something when routing to /api/foobar/foobar
        }
    }
    

    同样的建议会发送到您的 HomeController(如果您真的想为其添加路由,并且该类中的每个方法都将根据其方法名称进行路由,例如 Index

    [RoutePrefix("foo/bar")]
    public class MyController : BaseController
    {
        public IActionResult Index()
        {
            return View(); //or something
        }
    
        public IHttpActionResult Contact()
        {
            return View(); //or something
        }
    }
    

    【讨论】:

    【解决方案3】:

    如果你想用/Foo/Bar/SomeAction 路由FooBarController.SomeAction,你可以尝试类似

        [Route("Foo/Bar/[action]")]
        public class FooBarController : ControllerBase
        {
                public IActionResult Index()
                {
                        // ...
                }
    
                public IActionResult SomeAction()
                {
                        // ...
                }
        }
    

    【讨论】:

      【解决方案4】:

      我设法让它(看起来)使用以下方法工作。

      [Route("Foo/Bar")]
      [Route("Foo/Bar/[action]")]
      public class FooBarController : Controller
      {
          [HttpGet("")]
          public IActionResult Index()
          {
              return RedirectToAction("SomeAction");
          }
      
          public IActionResult SomeAction()
          {
              return View();
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-21
        • 1970-01-01
        • 2017-10-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多