很多刚开始使用asp.net mvc的朋友,对View的目录结构不太适应,虽然这种目录结构并无不良影响,但层次感确实比较差。对于稍大一些的项目,存在许多Controller,这些controller如果不进行分类组织,都放在一个文件夹下,就是想找到它们也很费劲,当然所对应的view也是一样,好在可以用Area分割组织项目,但使用者很快会发现Area其实就是原有结构的克隆,在主干上通过Areas文件夹,延伸出一个一模一样的东西,显得非常怪异。
其实大多数人希望象asp.net webform那样,能够自由组织目录结构。对于webform来说,访问某一页面,就是经过一个完整的路径访问所对应的那个物理文件,目录怎么组织都可以,而对于mvc很显然不是这样的,其视图的路径由return View(url)中的url决定。假如你是一个不怕麻烦的人,看到这里就可以了,老老实实的指定这个url如return View("~/Views/X/Y/Z/index.cshtml")就行了,但事实上大多数人都很懒,还是直接return View()或return View(model)来得比较爽,按默认的配置自动查找和匹配相应的view。
asp.mvc 3有很多扩展点,其中视图引擎(ViewEngine)就是一个,通过对视图引擎的重写能达到自定义view目录结构的目的。下面通过示例来说明具体方法。
问题:asp.net mvc 3项目中,在原默认结构的基础上,添加了两个Area,一个是Admin,另一个是User,如何组织目录结构?
答曰:
1.controller目录结构随意,毫无影响,甚至可以做为类库放到另一个项目中,如果只想放在一个项目中,建议结构如下:
Controllers
--Admin
|--Controller1
|--Controller2
|--Controller..
--User
|--Controller1
|--Controller2
|--Controller..
--Home(原默认Controller)
在Controllers下新建Admin,User,分别把Areas中的Admin和User中的Controllers移到新建的对应目录中,修改相关类的命名空间(也可不修改)。
然后到对应的AreaRegistration文件中注册控制器命名空间,如在AdminAreaRegistration.cs文件中:
当然可以灵活设置控制器的结构,可以有更深的层次,根据需要只需在new string[]{......}加入多个注册就行了。如果要更改默认主控制器层次结构,还得到Global.asax.cs中注册。
2.View目录结构,按Area--->Controller--->Action组织
Views
--Admin
|--Controller1
|--*.cshtml
|--Controller2
|--*.cshtml
|--Controller..
--User
|--Controller1
|--*.cshtml
--Home(默认主Controller)
|--*.cshtml
--Shared
|--*.cshtml
将areas中Admin,User相关view文件移到对应目录
3.删除Areas目录
4.新建一个CustomerRazorViewEngine.cs文件,代码如下:
public class CustomerRazorViewEngine : RazorViewEngine {
public CustomerRazorViewEngine(): base() {
//Area视图路径其中{2},{1},{0}分别代表Area名,Controller名,Action名
AreaViewLocationFormats = new[] { "~/Views/{2}/{1}/{0}.cshtml", "~/Views/Shared/{0}.cshtml" };
//Area模版路径
AreaMasterLocationFormats = new[] { "~/Views/Shared/{0}.cshtml" };
//Area的分部视图路径
AreaPartialViewLocationFormats = new[] { "~/Views/{2}/{1}/{0}.cshtml", "~/Views/Shared/{0}.cshtml" };
//主视图路径
ViewLocationFormats = new[] { "~/Views/{1}/{0}.cshtml", "~/Views/Shared/{0}.cshtml" };
//主模版路径
MasterLocationFormats = new[] { "~/Views/Shared/{0}.cshtml" };
//主分部视图路径
PartialViewLocationFormats = new[] { "~/Views/{1}/{0}.cshtml", "~/Views/Shared/{0}.cshtml" };
}
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath) {
return base.CreatePartialView(controllerContext, partialPath);
}
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath) {
return base.CreateView(controllerContext, viewPath, masterPath);
}
protected override bool FileExists(ControllerContext controllerContext, string virtualPath) {
return base.FileExists(controllerContext, virtualPath);
}
}
protected void Application_Start() {
AreaRegistration.RegisterAllAreas();
ViewEngines.Engines.Clear();
//注册自定义视图
ViewEngines.Engines.Add(new CustomerRazorViewEngine());
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}