这个例子反映了Module与Handler沟通的方式,我再来举个Module自身沟通的例子,就说UrlRoutingModule吧,它订阅了二个事件:
- protected virtual void Init(HttpApplication application)
- {
- application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);
- application.PostMapRequestHandler += new EventHandler(this.OnApplicationPostMapRequestHandler);
- }
在OnApplicationPostResolveRequestCache方法中,最终做了以下调用:
- public virtual void PostResolveRequestCache(HttpContextBase context)
- {
- // ...............
- RequestData data2 = new RequestData {
- OriginalPath = context.Request.Path,
- HttpHandler = httpHandler
- };
- context.Items[_requestDataKey] = data2;
- context.RewritePath("~/UrlRouting.axd");
- }
再来看看OnApplicationPostMapRequestHandler方法中,最终做了以下调用:
- public virtual void PostMapRequestHandler(HttpContextBase context)
- {
- RequestData data = (RequestData)context.Items[_requestDataKey];
- if( data != null ) {
- context.RewritePath(data.OriginalPath);
- context.Handler = data.HttpHandler;
- }
- }
看到了吗,HttpContext.Items为Module在不同的事件中保存了临时数据,而且很方便。
强大的背后也有麻烦事
前面我们看到了HttpContext的强大,而且还提供HttpContext.Current这个静态属性。这样一来,的确是【在任何地方都能找到它】。想想我们能做什么?我们可以在任何一个类库中都可以访问QueryString, Form,够灵活吧。我们还可以在任何地方(比如BLL中)调用Response.Redirect()让请求重定向,是不是很强大?
不过,有个很现实的问题摆在面前:到处访问这些对象会让代码很难测试。原因很简单:在测试时,这些对象没法正常工作,因为HttpRuntime很多幕后的事情还没做,没有运行它们的环境。是不是很扫兴?没办法,现在的测试水平很难驾驭这些功能强大的对象。
很多人都说WebForms框架搞得代码没法测试,通常也是的确如此。
我看到很多人在页面的CodeFile中写了一大堆的控件操作代码,还混有很多调用业务逻辑的代码,甚至在类库项目中还中访问QueryString, Cookie。再加上诸如ViewState, Session这类【有状态】的东西大量使用,这样的代码是很难测试。
换个视角,看看MVC框架为什么说可测试性会好很多,理由很简单,你很少会需要使用HttpRequest, HttpRespons,从Controller开始,您需要的数据已经给您准备好了,直接用就可以了。但MVC框架并不能保证写的代码就一定能方便的测试,比如:您继续使用HttpContext.Current.XXXXX而不使用那些HttpXxxxxBase对象。
一般说来,很多人会采用三层或者多层的方式来组织他们的项目代码。此时,如果您希望您的核心代码是可测试的,并且确实需要使用这些对象,那么应该尽量集中使用这些强大的对象,应该在最靠近UI层的地方去访问它们。可以把调用业务逻辑的代码再提取到一个单独的层中,比如就叫“服务层”吧,由服务层去调用下面的