路由 - WebAPI 和 MVC 在一个项目中
Routing - WebAPI and MVC in one project
我有 2 个控制器。两者都与 Bar(Foo 的子级)打交道。
其中一个是针对 MVC 的 returns 视图。
[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 class,我可以访问 API 控制器(例如:/api/foo/bar/{id})和 MVC 控制器(对于示例:/FooBar/SomeAction)
[Route("Foo/Bar")]
但是当我这样做时,路由被弄乱了,我在尝试访问 /Foo/Bar/SomeAction
时收到以下错误
AmbiguousMatchException: The request matched multiple endpoints. Matches:
Controllers.MVC.FooBarController.Index
Controllers.MVC.FooBarController.SomeAction
当您没有应用该属性时,FooBarController 使用常规路由,您可能已经默认使用了该路由。它通常将 Index 作为默认操作,并允许您指定操作名称,因此一切正常。
应用属性时,此控制器中的所有操作现在都使用属性路由。这两种路由类型没有组合,您只能使用其中一种。请注意
"With attribute routing the controller name and action names play no
role in which action is selected."
(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()
{
// ...
}
}
是的,它更冗长。来自同一来源:
Attribute routing requires more input to specify a route; the
conventional default route handles routes more succinctly. However,
attribute routing allows (and requires) precise control of which route
templates apply to each action.
对于您的 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(如果您真的想为其添加路由,那么 class 中的每个方法都将根据它们的方法名称进行路由,例如 Index
)
[RoutePrefix("foo/bar")]
public class MyController : BaseController
{
public IActionResult Index()
{
return View(); //or something
}
public IHttpActionResult Contact()
{
return View(); //or something
}
}
如果你想用 /Foo/Bar/SomeAction
路由 FooBarController.SomeAction
,你可以尝试
[Route("Foo/Bar/[action]")]
public class FooBarController : ControllerBase
{
public IActionResult Index()
{
// ...
}
public IActionResult SomeAction()
{
// ...
}
}
我设法使用以下方法使其(看起来)正常工作。
[Route("Foo/Bar")]
[Route("Foo/Bar/[action]")]
public class FooBarController : Controller
{
[HttpGet("")]
public IActionResult Index()
{
return RedirectToAction("SomeAction");
}
public IActionResult SomeAction()
{
return View();
}
}
我有 2 个控制器。两者都与 Bar(Foo 的子级)打交道。
其中一个是针对 MVC 的 returns 视图。
[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 class,我可以访问 API 控制器(例如:/api/foo/bar/{id})和 MVC 控制器(对于示例:/FooBar/SomeAction)
[Route("Foo/Bar")]
但是当我这样做时,路由被弄乱了,我在尝试访问 /Foo/Bar/SomeAction
时收到以下错误AmbiguousMatchException: The request matched multiple endpoints. Matches:
Controllers.MVC.FooBarController.Index
Controllers.MVC.FooBarController.SomeAction
当您没有应用该属性时,FooBarController 使用常规路由,您可能已经默认使用了该路由。它通常将 Index 作为默认操作,并允许您指定操作名称,因此一切正常。
应用属性时,此控制器中的所有操作现在都使用属性路由。这两种路由类型没有组合,您只能使用其中一种。请注意
"With attribute routing the controller name and action names play no role in which action is selected."
(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()
{
// ...
}
}
是的,它更冗长。来自同一来源:
Attribute routing requires more input to specify a route; the conventional default route handles routes more succinctly. However, attribute routing allows (and requires) precise control of which route templates apply to each action.
对于您的 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(如果您真的想为其添加路由,那么 class 中的每个方法都将根据它们的方法名称进行路由,例如 Index
)
[RoutePrefix("foo/bar")]
public class MyController : BaseController
{
public IActionResult Index()
{
return View(); //or something
}
public IHttpActionResult Contact()
{
return View(); //or something
}
}
如果你想用 /Foo/Bar/SomeAction
路由 FooBarController.SomeAction
,你可以尝试
[Route("Foo/Bar/[action]")]
public class FooBarController : ControllerBase
{
public IActionResult Index()
{
// ...
}
public IActionResult SomeAction()
{
// ...
}
}
我设法使用以下方法使其(看起来)正常工作。
[Route("Foo/Bar")]
[Route("Foo/Bar/[action]")]
public class FooBarController : Controller
{
[HttpGet("")]
public IActionResult Index()
{
return RedirectToAction("SomeAction");
}
public IActionResult SomeAction()
{
return View();
}
}