Visual Studio 2017 CE中.NET Core 2.0项目的Anchor Tag Helper调用API控制器问题
嘿,我太懂你这种场景下的头疼了——同时维护MVC和Web API控制器,还撞上了同名的StoresController,Edit页面的Delete链接大概率是出了路由匹配的问题对吧?别慌,咱们一步步来搞定它。
先复盘下你的项目配置,确认我没理解错:
- 开发环境:Visual Studio 2017 Community Edition,基于.NET Core 2.0
- 目录结构:
API目录放Web API控制器,Controllers目录放标准MVC控制器 - 路由配置:
- API下的
StoresController用了特性路由:[Route("api/[controller]")] - MVC下的
StoresController依赖Startup.cs里的默认路由
- API下的
这种情况下最常见的问题是:当你在MVC Edit页面生成Delete链接时,路由系统可能错误地把请求导向API控制器,或者反过来——毕竟两个控制器同名,路由系统得猜你要哪个。
下面给你几个靠谱的解决方案,按推荐程度排序:
1. 用命名空间约束精准匹配控制器(首推)
这是最干净的解决方式,直接告诉路由系统:MVC默认路由只找Controllers目录下的控制器,API路由只找API目录下的。
首先修改Startup.cs里的MVC路由配置,加上命名空间约束:
app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}", constraints: new { namespace = "YourProjectName.Controllers" } // 替换成你的MVC控制器命名空间 ); });
然后给API控制器的路由加上命名空间限定(或者直接保持目录对应的命名空间即可):
namespace YourProjectName.API { [Route("api/[controller]")] [ApiController] public class StoresController : ControllerBase { // 你的API动作方法 } }
这样路由系统就不会搞混两个控制器了,请求会精准匹配到对应命名空间下的那个。
2. 给MVC控制器显式指定路由模板
如果不想折腾命名空间,也可以给MVC的StoresController的每个动作加上特性路由,明确和API路由区分开:
namespace YourProjectName.Controllers { public class StoresController : Controller { [Route("stores/edit/{id}")] public IActionResult Edit(int id) { // Edit页面逻辑 } [Route("stores/delete/{id}")] [HttpPost] public IActionResult Delete(int id) { // Delete逻辑 } } }
同时在Edit页面生成Delete链接时,一定要明确指定控制器和动作,避免路由猜测:
<!-- 用HtmlHelper --> @Html.ActionLink("Delete", "Delete", "Stores", new { id = Model.Id }, new { @class = "btn btn-danger" }) <!-- 或者用标签助手(更推荐) --> <a asp-action="Delete" asp-controller="Stores" asp-route-id="@Model.Id" class="btn btn-danger">Delete</a>
3. 调整路由优先级(应急方案)
如果临时不想改太多代码,可以通过调整路由优先级来强制路由系统优先匹配你想要的控制器。
特性路由的优先级默认高于常规路由,所以如果你的Delete链接想优先走MVC,可以给API的特性路由设置更高的Order值(值越大优先级越低):
[Route("api/[controller]", Order = 1)] public class StoresController : ControllerBase { // API动作 }
不过这种方式不如前两种稳定,后续新增路由容易再出问题,所以只建议临时用用。
总的来说,核心就是让路由系统能明确区分两个同名控制器,命名空间约束是最一劳永逸的方法。
内容的提问来源于stack exchange,提问作者Sam

