我正在过渡到在项目中使用区域
几个月以来我一直在做类似的事情,但从一个旧的 WebForms 项目开始,通过 VS 2013 的 Add -> New Scaffolded Item... 功能添加 MVC 组件,以便在服务器端利用 MVC 的结构和路由。我也一直在服务器端合并 WebAPI 和 SignalR。我绝对仍然是一个初学者,但在类似的过程中可能会走得更远一些,这里有一些关于你想要实现的想法和问题:
- 删除创建的文件夹之一
- 稍微修改 web.config 文件
- 使用一些默认值添加一个或两个新文件
你在什么环境下开发?例如,如果您使用 VS 2013 的脚手架,您很可能会修改 T4 模板以防止或重定向文件夹、类等的创建。 Here 是一个帖子地址,您可以在其中找到这些模板,here 只是 T4 的众多介绍之一。您机器上模板的路径将根据 VS 版本而有所不同。通过修改或创建新模板,您应该能够相对容易地完成以上所有 3 点。如果您在这样的环境中工作,我将尝试详细说明您可能如何修改开箱即用的模板(可能已经有很多帖子可供您参考,但它们会做得更好)。
如果您使用的是 MVC 5 或更高版本,我建议您使用属性路由。在 API 范式中工作时,这似乎更标准(继承自 ApiController 而不是 Controller),但我发现将其扩展到传统的 MVC 控制器非常有用。
假设 MVC 5,我建议修改 AppStart\RouteConfig.cs 的 RegisterRoutes() 方法,以启用属性路由,然后添加一个包罗万象的路由,例如:
routes.MapMvcAttributeRoutes();
routes.MapRoute(
"NotFound",
"{*url}",
new {
controller = "Error",
action = "Index"
});
那时我会删除 xAreaRegistration.cs 文件,并从Global.asax 中删除对RegisterAllAreas() 的调用,但您不必走那么远。然后我根据需要用属性装饰我的控制器的类(无论它们住在哪里)和它们的方法。使用属性路由,我已经能够将自己从传统的 MVC 约定中解脱出来。我仍然可以使用它们,但我可以将控制器放置在项目中的任何位置,并轻松定义它们的动作路线。
话虽如此,您可能应该遵循一些类似路由组的组织标准,以便随着项目的发展,您不会发现自己浪费大量时间来搜索与某组路由匹配的所有控制器/动作。
这里有一个简单的例子来说明这实际上是如何从 URI 转换为方法调用的:
如果我有控制器ctl 和动作act,逻辑上 区域ar,URI 为http://localhost/ar/ctl/a/1,将通过使用属性路由到下面的MyControllerNameDoesNotMatter.Index(1)装饰如:
[RouteArea("ar")]
[RoutePrefix("ctl")]
public class MyControllerNameDoesNotMatter : Controller {
...
[Route("a/{optionalParamDefaultsToNegativeOne=-1}")]
public ActionResult Index(int optionalParamDefaultsToNegativeOne) {
...
}
}
这种查看区域的方式比物理更符合逻辑,因为MyControllerNameDoesNotMatter.cs 文件不必位于Area\ar\Controllers 文件夹中。自从采用这一点后,我实际上已经不再使用 Area 脚手架,而是在非常高的层次上布置应用程序模块 - 想想可能是独立 SPA 的子应用程序。
我已尝试基于“catch-all”路由属性,并将其从RouteConfig.cs 中删除,但我未能成功完成此操作。问题是路由优先级。它可以很好地作为无效路线的包罗万象。但是对于有效路由,最终会匹配多 (2) 个路由,因为这两个属性路由具有相同的优先顺序。而在RouteConfig.cs 中定义的包罗万象,在注册所有属性路由后,属性路由优先。我发现了试图解决这个问题的混合答案。在某些时候,Route 属性似乎有一个Number 或Order 参数,但我没有运气。这似乎是一个悬而未决的问题。 Just one of many SO questions,没有得到答复。
编辑以考虑 mvc4 标记
在发布之前我没有看到 mvc4 标签。有一些可用的 nuget 包可以实现大部分相同的功能,例如用于早期版本的 MVC 的 scaffolding 和 attribute routing。