就个人感觉而言。ASP.NET MVC是一种非常反人类的设计。(我没有接触过Java的MVC,不知道两者是否一样。如果一样,那么搞Java的同学也挺可怜。)尤其是MVC的路由机制,灰常灰常反动。路由所带来的“美观的”URL,通过合理的文件层次布局+URL重写机制同样可以解决。但显然文件目录结构的方式,更直观明了,贴近人们的自然思路。可惜不管我们如何吐槽,萨蒂亚•纳德拉估计是不会听的。

  MVC的默认组织机构是扁平的。所有的Controller都是平级的。在大型项目中,这完全是一个灾难。当需要上百个甚至数百个Controller,或是为了让代码“自说明”时(指合理的给方法、文件命名,使阅读者在没有注释的时候也能直接读懂开发者的意图),很多Controller需要同名时,尤其让人崩溃。路是死的,人是活的。为了解决这一问题,聪明的程序猿想出了很多办法。比如利用Area机制、重写视图匹配机制、重写MVC框架等等。我们的OA系统中也有近百个Controller,不提前规划好路由,后续的工作我们就无法展开。所以,在这一节,我们就来聊聊其中两种不对MVC做大手术的方式。


(仅仅一个小功能模块就需要10多个Controller,在大型项目中,甚至需要数百个Controller,对项目管理而言,如不进行合理划分、管理,而按照mvc默认的平级存放,无疑会带来灾难性的后果。注:本图已对功能模块进行按目录划分)

MVC大型项目常见组织方式1——重写视图匹配机制,实现MVC多级目录

  该方式的核心要点是:根据功能划分,对Controller和View进行多级目录处理(如上图)。然后通过路由优先级和重载MVC自带的视图匹配逻辑的方式,达到精确控制URL与Controller、Views进行匹配。进行这是最接近自然思维的处理方式,合理而精细的安排路由优先级的情况下,可以做到非常深的目录层次。在我们的示例项目中,也将采用这种办法。

  1. 根据功能划分,对Controller和View进行多级目录划分。
  2. 注册路由列表,通过优先级的方式,将路由和Controller一一对应。
  3. 重载MVC视图匹配逻辑,将View和Controller一一对应。

  

 namespace EasyFast.Web
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); //ASP.NET Web API Route Config
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
); routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new string[] { "EasyFast.Web.Controllers" }
);
}
}
}
 namespace EasyFast.Web.Areas.Admin
{
public class AdminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Admin";
}
} public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Admin_Config",
"Admin/Config/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
new string[] { "EasyFast.Web.Areas.Admin.Controllers" }
);
}
}
}

  如上代码所示。我们给 App_Start->RouteConfig.cs 文件增加了namespace参数,并指定了完整的命名空间 “EasyFast.Web.Controllers” 。在一个MVC应用中,指定了该命名空间后,就可以解决Areas和站点根目录中有重名的Controller问题。如站点首页是HomeController,后台首页也是HomeController此时MVC会检测到两个重名的控制器,系统会要求给其中一个控制器指定完整命名空间。我们的一般做法是给App_Start文件中的路由配置文件指定命名空间。否则我们就必须为每个Areas指定命名空间(其他Areas里也可能有叫HomeController的控制器)。当然了,您也可以给App_Start和所有的Areas中的路由都指定命名空间,但是,只指定App_Start->RouteConfig.cs无疑是一种简洁的做法。

  细心的朋友可能会看到:我们给App_Start->RouteConfig.cs和Areas.Admin.AdminAreaRegistration.cs都指定了命名空间。这是因为在我们的Admin区域下。也会有多个重名的控制器(例如HomeController)。同时,要注意:有目录划分的路由要写在默认路由的前面,且不可和默认路由重名。

(同一个Areas里出现两个同名的HomeController控制器。系统设置这个模块的首页和后台首页控制器重名。只要涉及到控制器重名,就必须给其中一个指定完整命名空间)

 namespace EasyFast.Web.Extend
{
public class EasyFastViewEngine : RazorViewEngine
{
public EasyFastViewEngine()
{
ViewLocationFormats = new[]
{
"~/Views/{1}/{0}.cshtml",
"~/Views/Shared/{0}.cshtml",
"~/Views/Areas/{1}/{0}.cshtml"//我们的规则
};
AreaViewLocationFormats = new[]
{
"~/Areas/{2}/Views/{1}/{0}.cshtml",
"~/Areas/{2}/Views/Shared/{0}.cshtml", "~/Areas/{2}/Views/Config/{1}/{0}.cshtml",
"~/Areas/{2}/Views/User/{1}/{0}.cshtml",
"~/Areas/{2}/Views/Case/{1}/{0}.cshtml", "~/Areas/{2}/Views/Config/Shared/{0}.cshtml",
"~/Areas/{2}/Views/User/Shared/{0}.cshtml",
"~/Areas/{2}/Views/Case/Shared/{0}.cshtml"
};
} public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
return base.FindView(controllerContext, viewName, masterName, useCache);
} public static void Config()
{
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new EasyFastViewEngine());
}
}
}
 namespace EasyFast.Web
{
public class MvcApplication : AbpWebApplication<EasyFastWebModule>
{
protected override void Application_Start(object sender, EventArgs e)
{
AbpBootstrapper.IocManager.IocContainer.AddFacility<LoggingFacility>(
f => f.UseAbpLog4Net().WithConfig("log4net.config")
);
EasyFastViewEngine.Config();//注册多级目录扩展
base.Application_Start(sender, e);
}
}
}

  如上代码。我们在web根目录下建立了Extend文件夹,并在其中新建了EasyFastViewEngine.cs文件。然后再文件内部,重载了MVC自带的视图查找逻辑。代码中的{2}、{1}、{0}是占位符,分别代表了Area、Controller、Action。这样一来,程序在实行时就会按照我们制定的查找顺序去指定的目录匹配View文件。通过合理的路由安排,这样做可以做到很深的目录层次结构。相信聪明的读者一定想到了如何扩展出三级、四级甚至更多级的目录。

  如此做法,本身也存在一定的不便。在具体Action上右键选择转到视图,或是在具体视图右键选择控制器时,VS会提示找不到对应的控制器或是视图。但这不是MVC的问题,而是VS自身的问题,VS在设计时应该没考虑过多级目录问题。同时,在Ctrl+F5运行程序时,浏览器会直接按照文件路径加载对应的cshtml文件,并报404错误。此时,需要我们手动修改URL路径,程序就能正常显示了。


(在具体View页面直接编译运行程序时,会显示404错误,此时手动修改URL地址即可解决)

MVC大型项目常见组织方式2——前后台独立,利用Area划分功能区域

  该方式不用对MVC做任何定制修改。只需要在项目架构里将前台、后台、用户中心等划分成多个web项目即可。然后在每个web项目里,根据功能群的划分,再独立建立Areas。如此做法,有三个直观的好处同样也有三个直观的缺陷。因为好处和缺陷都是同样显而易见,我们就不一一详细介绍了,只列出总结的提醒,供大家选择判断。

好处:

  1. 不用对MVC框架做任何调整,可以方便的从视图或是控制器自由切换。
  2. 多个web项目意味着可以生成多份程序,可以分别部署到不同的服务器上,以提高站点负载。
  3. 团队开发时,不同的项目可以交付不同的开发人员,最大程度上避免沟通成本。

坏处:

  1. 最大只能做到三级目录。(其实这不算什么坏处,三级目录对一个大中型项目来说,是足够用的,如感觉不够用,更多的应该考虑如何合并功能群而不是拓展更深的目录层次)。
  2. 共享与资源锁问题。几乎在所有的应用程序中,都有前后台公用的css、js、配置文件甚至代码段本身等等等等,当前后台独立时,就需要为这些需要共享资源安排合适的位置而头疼了。在例如在实现内存缓存时,我们都要求缓存类是单例的,但是,单例是应用程序范围内的单例。前台和后台分别部署,显然是两个应用程序,代码中的单例缓存类也就彻底失效了。
  3. 部署问题。任意修改非web项目后,都需要多次部署。如再考虑上CDN或是缓存服务器什么的,部署将会更加麻烦。
         public long Add(UserTypeInput model)
{
long _result = ;
var data = Mapper.Map<UserTypeInput, Core.Entities.UserType>(model);
lock (lockHelper)
{
if (!CheckName(model))
{
_result = _userTypeRepository.InsertAndGetIdAsync(data).Id; }
}
return _result;
}

  考虑如上代码。假设前后台都调用Add方法时,lock控制段显然会失效。这样一来,新增数据时,重名检测方法会失效,有可能会造成前后台分别录入了一条重名的人员类别。


(前后台分属不同的项目,利用Area实现系统设置、案件管理、用户管理等功能群,此做法只能实现三级目录,功能群模块(具体Area)/功能组(Controller)/具体功能(Action))

二、处理MVC多级目录问题——以ABP为基础架构的一个中等规模的OA开发日志的更多相关文章

  1. 一、项目基础架构(附GitHub地址)——以ABP为基础架构的一个中等规模的OA开发日志

    前言: 最近园子里ABP炒的火热.看了几篇对于ABP的介绍后,深感其设计精巧,实现优雅.个人感觉,ABP或ABP衍生品的架构设计,未来会成为中型Net项目的首选架构模式.如果您还不了解ABP是什么,有 ...

  2. MVC 多级目录菜单

    MVC多级目录菜单  ----- 简单模拟 Model ---- cs { public class Class1 { public int ID{get;set;} public int paren ...

  3. MVC 多级目录(控制器) 路由重写 及 多级Views目录 的寻找视图的规则

    转自:[原]Asp.net Mvc   多级控制器 路由重写 及 多级Views目录 的寻找视图的规则 asp.net mvc 为了更好的控制views的页面存放,和控制器的可读性,需要分开多级目录来 ...

  4. asp.net mvc多级目录结构和多级area实现技巧

    今天在工作要实现这个多级area.其原因是这个项目需要多级的功能,大的类别里有小的类别,小的类别里有具体的功能项,每一个功能项还有若干动作Action,所以在菜单和mvc工程的结构上都需要有体现多级的 ...

  5. asp.net mvc 多级目录结构

    ikmb@163.com ASP.NET MVC默认的文件组织和URL访问都是一级,我们通常要将一个功能模块组织到一个目录下.方法是:1.文件组织 分别在Controllers和Views文件夹下建议 ...

  6. php mkdir 创建多级目录实例代码

    先介绍一下 mkdir() 这个函数 mkdir($path,0777,true); 第一个参数:必须,代表要创建的多级目录的路径. 第二个参数:设定目录的权限,默认是 0777,意味着最大可能的访问 ...

  7. Asp.net Mvc 多级控制器 路由重写 及 多级Views目录 的寻找视图的规则 (多级路由) 如:Admin/Test/Index

    http://blog.csdn.net/buhuan123/article/details/26387427 目录(?)[-] 1那么我们再来看我们需要的访问方式如下图 razor视图的地址写成通配 ...

  8. MVC 设置项目默认起始页和多级目录的路由配置

    我们新建一个MVC的项目 默认的路由是这样的,但是由于一些需求,我们需要对Controllers按照一些规则分类. 比如说我们在Controllers下面建了一个School的文件夹,然后建了一个St ...

  9. Windows Azure Storage (22) Azure Storage如何支持多级目录

    <Windows Azure Platform 系列文章目录> 熟悉Azure平台的读者都知道,Azure Blob有三层架构.如下图:(注意blob.core.chinacloudapi ...

随机推荐

  1. JavaSE复习总结之集合(Collection)

    Java早期版本只给集合类库提供了很少的一组类,但是随着Java版本的升级,Java集合类库越来越充实.集合类库里面存放的,是各式各样的数据容器,我们基本都学过数据结构这门课,数据结构所讲的就是ADT ...

  2. 转:软件架构入门 (from 阮一峰)

    说明:其中讲到了 5 种的架构模型,很不错. from: http://www.ruanyifeng.com/blog/2016/09/software-architecture.html

  3. NOIP模拟赛 行走

    题目描述 “我有个愿望,我希望走到你身边.” 这是个奇异的世界,世界上的n-1条路联结起来形成一棵树,每条路有一个对应的权值ci. 现在我会给出q组询问或操作. 每次询问我会从一个x点走到y点,初始在 ...

  4. .Net程序员学习Linux最简单的方法

    有很多关于Linux的书籍,博客.大多数都会比较“粗暴“的将一大堆的命令塞给读者,从而使很多.NET程序员望而却步.未入其门就路过了. 所以我设想用一种更为平滑的学习方式, 就是在学习命令时,先用纯语 ...

  5. gitlab配置邮件通知功能操作记录

    之前已经介绍了gitlab的部署http://www.cnblogs.com/kevingrace/p/5651402.html但是没有配置邮箱通知功能,今天这里介绍下gitlab安装后的邮箱配置操作 ...

  6. PAT 1018. 锤子剪刀布 (20)

    现给出两人的交锋记录,请统计双方的胜.平.负次数,并且给出双方分别出什么手势的胜算最大. 输入格式: 输入第1行给出正整数N(<=105),即双方交锋的次数.随后N行,每行给出一次交锋的信息,即 ...

  7. Div和Span标签显示与隐藏

    本实例中,学习jQuery的知识,显示与隐藏网页上的div或是span标签. 实际环境中,也许是根据某些条件进行,符合条件时,对某个或是某个div或是span标签时行显示与隐藏. 主要是学习jQuer ...

  8. Python之线程、进程和协程

    python之线程.进程和协程 目录: 引言 一.线程 1.1 普通的多线程 1.2 自定义线程类 1.3 线程锁 1.3.1 未使用锁 1.3.2 普通锁Lock和RLock 1.3.3 信号量(S ...

  9. eclipse/intellij Idea集成jetty

    jetty相对weblogic.jboss.tomcat而言,启动速度快,十分方便开发调试,以下是eclipse里的使用步骤: 一.eclipse->Marketplace里搜索 jetty 一 ...

  10. 2015-2016-2 《Java程序设计》教学进程

    2015-2016-2 <Java程序设计>教学进程 目录 考核方式 寒假准备 教学进程 第00周学习任务和要求 第01周学习任务和要求 第02周学习任务和要求 第03周学习任务和要求 第 ...