随笔- 54  文章- 3  评论- 762  阅读- 39万 

  被称为一个漂亮的Asp.net MVC应用,从代码角度来看,我认为得满足这三点:

1. 使用依赖注入框架。

2. 不要直接依赖Cache, HttpContext等。

3. View中不要条件逻辑。

  当然不只是这三点,还有很多。我个人拿它们出来,是认为这些很重要但是经常被忽视。

 

  对于第1点,优点在于松耦合,可测试性很好。如果在Controller里面想要使用某些Service,要么new出来,要么用单例的形式,如UserService.Instance,这样想对Controller写单元测试都不容易,它和这些Service耦合太紧密,无法将这些Service替换成Stub实现。因此,松耦合是必须的。要实现这个功能,必须让依赖注入框架来创建Controller,才有可能注入依赖并组装对象。MVC里面有一个ControllerFactory的东西,可以使用来达到这个目的。

  a. 写一个类,继承自DefaultControllerFactory,例如 UnityControllerFactory : DefaultControllerFactory

  b. 覆盖方法GetControllerInstance,使用依赖注入框架来创建Conroller

  c. 修改Global.asax.cs, 在Application_Start内注册使用自己的ControllerFactory,

     ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory())

  d. 对Controller进行构造函数注入,例如:

      public class UserController : Controller

      {

           public UserController(IUserService, userService, IMessageService messageService)

           …

       }

    从现在开始,所有的Controller都是通过依赖注入框架来创建的,新增的Service就在依赖注入框架里面注册,Controller要使用哪些Service就往构造函数里加,反正框架会注入进来。

 

    第2点, 类如HttpContext.Current.Session[“xxx”] = …, HttpContext.Current.Cache.Insert…此样的代码充斥在各个角落。有问题吗?还是老问题,可测试性,可替换性。

    像HttpContext这种东西,几乎是不能Mock或者Stub的,只要代码中使用了HttpContext,可以说它就没法做单元测试。为什么很多人都会这么用呢,一个原因是图方便图简单,二是没有写单元测试。要用Session直接用就好了,封装一下再用多麻烦啊,这就是图简单。

    解法很简单,对HttpContext进行封装,例如ISessionProvider, ICacheProvider,然后通过依赖注入框架,注入到Controller中去,这样的结果是代码可测试性高,而且想改变Cache机制也很方便。

    意识不够。什么意识?让代码松耦合的意识。使用静态方法,静态变量,直接new依赖的对象,这些都是松耦合的反例。我们写代码的时候要规避它们。即使我们不用TDD(极端一点来说,现在不写单元测试),脑子里也要清楚记得,面向对象的法则、松耦合的一些原则等等,然后反应到代码上去。

    这一点,记得好像园子里以前有人提到过。

 

    最后一点,View中不写条件逻辑。View中一旦加入条件判断,就会使得代码特别难以维护,难以理解。如果在aspx文件中,看到以下的代码:

   <% if (条件1) { %>

    <div>

      …

      <% if(某某条件) { %>

       …

       <% } %>

     </div>

   <%} else if (条件2) { %>

      …

   <% } else { %>

      …

   <% } %>

   这样的View让人很怕去改,生怕哪里改错了而自己又不知道。因为它写的太混乱,逻辑和显示穿插在一起,如果再混着一些动态的html元素,那就真的只能谁写的谁来弄。

   我们可以怎样做呢?如果是比较复杂的条件逻辑,就放到Controller里面去做,然后返回不同的View。这样View又很简单,这些逻辑又可以被测试。没有谁规定,一个Action只能对应一个View。跟Class的道理一样,Class职责过多,就得进行拆分。View的逻辑过于复杂也得进行拆分。

  这么拆分以后,有可能会出现几个View有重复的部分。那就具体情况具体解决了,可以使用ViewHelper,也可以把重复的东西再独立出来,不同的View来复用。记住,View是代码的一部分,不要觉得涉及到Html的部分乱就乱点。View也是需要持续被重构的。

  这一篇着重强调的是,漂亮的代码有良好的可测试性。

 posted on   紫色阴影  阅读(3810)  评论(29编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
我要啦免费统计
点击右上角即可分享
微信分享提示