在有Maverick.Net(以下称NMav)之前已经有Maverick(for Java)了,NMav和Maverick一样是一个轻量级的MVC框架,说它是轻量是因为Maverick直奔主题,除了实现MVC模式以外没有像Struts一样定义一个庞大的Taglib库那样的枝枝叶叶。
NMav是一个完整的M—V-C,这一点不像UIP(详细介绍看前章)。NMav在实现上体现它的精干,具有比较强的灵活性,它提供了Xml和Page两类View的支持,提供了几类Controller(主要对Model的使用上的分),提供了基于Asp.net的Controller的支持(称之为Asp页面控制型)和基于URL请求总控的Controller的支持(称之Dispatcher控制型)。
先来看看NMav的组成结构:
Controller--控制器,其支持四种控制:
Throwaway:没有Model类
FormUser:Model由用户指定,就是说Model类(比如你定义了一个UserInfo用户DTO,
如果包含了UserId 和Password的地字段),它通过public abstract object MakeForm(IControllerContext cctx) 一个抽象方法要求从此类继承的Controller类实现其方法而获得用户定义的Model实例,比如这里可以在MakeForm()方法中加上一句: return new UserInfo();,实现创建一个UserInfo的Model实例。
ThrowawayForm: Model就是本身,就是说此类Controller类同时包含了Model的信息
把UserInfo的定义放到Controller类中,那就省了UserInfo这个类了。
ThrowawayFormUser:是ThrowawayForm和FormUser的结合,可以采用自己指定Model
类(重载MakeForm方法),也可以不做任何动作,就默认为Controller本身类。
View――视图,有5种:
DocumentView:一般的View都为此类型
RedirectView:是重定向View类型,这跟一般的页面重定向没什么区别,只是它重定向到另一个Command而非页面
NullView:什么都不做;
TrivialView:这类view一般作为引导作用,如果比如本身的View没有含有页面,但
是只要在外面加一个主页面
XmlSerializingView:是对Xml作为页面呈现的一类View
Transform――页面的外套,做为View中一个重要部分,Transform的引入为Asp.net下不能采用像Jsp中那样使用Include指令包含进一个页面提供了一个很好的思路。然而Transform是和Include指令的作用是朝方向相反的,它是把Page放到有Transform指定的View中去,Transform就是外套。当然外套也有两套:DocumentTransform(一般页面)和XsltTransform(Xml页面)。
Command――就是一次调用页面的操作指令,当前View的情况下,如果返回不同下个View就会被Controller调用到下一个页面。如果用过Struts的话这个就能很好理解了,似乎我这样表达还是没到点上,从下文的配置文件中联系起来看就很好理解了。
Configuration――配置以及配置读取。
Dispatcher――这个在UIP中是没有的,是派发器,页面提交就到这里来,然后它根据页面传过来的状态上下文来分发请求到相关的Command,再调用合适的View来呈现,就是上文所说的总控(也不知道这样说是否合适)。NMav通过Dispachter类来实现,Dispatcher是从IHttpHandler接口继承的,因此它能在做为总控用,Dispatcher在整个NMav运行时只有一个实例,并且存放在Application的变量Hashtable中。
Context――上下文,递交请求信息到Dispatcher,由 MaverickContext主要包含了Model,HttpContext以及Transform等信息。
NMav对多语言的支持,从NMav的设计初衷来看只要在View中指定如mode=”语言类别”,就表示此View对该语言的支持,那么就可以通过相同的View名称指定不同Path的页面,而不用像每个页面从资源文件中去读取不同语言的Label信息,毕竟不同的语言对应着不同的使用习惯和不同的文化。(呵呵)
其它的要说的是NMav的灵活性还体现配置上,它可以由用户自己去继承实现自己的Factory,可以由这些Factory创建运行的对象实例。 所以,分析NMav的过程你能发现很多的Factory。
这里有必要对NMav的运行过程了解一下:
在采用“Dispatcher控制型”(见上文)时,NMav的运行过程是这样的:在运行这种模式时,需要在IIS加入对文件类型的支持,添加完成如扩展为.m的与aspnet_isapi.dll的配置后,再在web.config中添加httphandler支持(
<httpHandlers>
<add verb="*" path="*.m" type="Maverick.Dispatcher, Maverick" />
</httpHandlers>
)。
在完成上面的配置后,在浏览器上敲入如http://locahost/NMav/test.m,因为上面的配置以及Dispatcher从IHttphandler继承的缘故,那么Dispatcher就会获得请求,Dispatcher先在Application缓存中找Dispatcher是否已经实例化的实例,如果没有那么会进行实例化一个Dispatcher,初次加载时从配置文件中加载配置信息,并且缓存起来。Dispatcher实例根据URL地址中的最后一个单词来作为一个Command,这里就是test,然后从的缓存中找到刚才从配置文件中配置的对应Command――test,转入对应的Command,然后调用Go()方法,在Go方法中Command调用Controller的Go()。在Controller的Go方法中会把页面的参数信息从HttpContext.Request.Params取出表单的输入参数,通过一个反射方法以名字相同来对Model的相应字段赋值,然后再根据得到的ViewName找到下一个view,转入页面的呈现,呈现过程中,会把外套一件一件穿上(这里是一个递归调用)。上述的过程,并没有调用页面后端的CS类。这就是说NMav就是把Asp.Net页面的CS类看作了Controller。但是,在这里,如果,你还沿用事件驱动开发的习惯,那么,这些事件将不会再被触发,进而微软众多的Server控件对事件也无效了,Server控件没用了!!!! 这个是一个后严重的后退。这就是所说的Asp.Net下的冲突问题,辛辛苦苦几十年,又回到了解放前。(……※(×#※×(◎)
还好,NMav采用了另外一套过程即“Asp页面控制型”(见上文),类ControllablePage是这种控制类型的唯一Controller,从Page继承(Page也是从IHttpHandler继承的,所以,Asp.Net的事件驱动除了又ViewState还要有IHttpHandler来截获处理,才能递交到Code-Behind的CS类中去),此方式下CS类还是直接作为Controller,但是这时就没有了对Model的支持。在这种方式下,请求先被Page的CS类获得,这时可以处理Server控件的事件,调用页面是在页面呈现时进行,ControllablePage重载了Render方法,这时再把请求交给Dispatcher,然后进行上面的过程。这种方法最大的缺点是没有了对Model的支持,上下文包含的Model信息再也不是model的信息,而是页面信息。再者,在我个人喜好来看,十分希望Controller还是能和CS类分开,这样的代码才更清晰。
大致说了一下NMav的运行过程,接下来我们还是用login的示例来讲解一下配置文件,以Dispatcher控制类型方式为例,假设有login.aspx,index.aspx,error.aspx,frame.aspx其cs类被杀了,有了一个myController的从FormUser继承的类,那么可以根据下面一组配置来实现一个登录成功到index页面,index页面还有一个Transform—frame.aspx,失败到error(一般要停在登录页面提示重新登录,这里仅做例子)。
public class myController:Maverick.Ctl.ThrowawayFormUser
{
//UserInfo 为自定义的DTO类
private UserInfo theUser;
public myController(){
}
public override object MakeForm(Maverick.Flow.IControllerContext cctx) {
theUser=new UserInfo();
return theUser;
}
protected override string Perform(){//这里会被Go()方法调用
//这里可以调用逻辑接口,此处简化
if(theUser.UserId=="allen" && theUser.Password=="123")
return "success";
else
return "fail";
}
}
Maverick.config的XML配置如下:
<?xml version="1.0"?>
<maverick version="2.0" default-view-type="document" default-transform-type="document"> //default*默认类型
<views>//全局view
<view id="loginSuccess" path="index.aspx"> //这里没有type,采用default-view-type
<transform path=" frame.aspx"/> //外套
</view>
<!—定义更多view-->
</views>
<commands>
<command name="login.m "> //这在URL敲入
<controller class="NMavTest1.Ctl.myController, NMavTest1"/> //Controller,如果只有单个View可省略
///用全局View在上面的Views中定义
///也可以不用在全局View中定义,直接
///<view name="success" path="index.aspx ">
/// <transform path="frame.aspx"/>
///</view>
<view name="success" ref=" loginSuccess ">//这里使用了引用
///
<view name="fail " type=”document” mode=”en” path="error.aspx" />//可以采用mode实现多语言
</command>
<!—command 此处可以添加更多command-->
</commands>
</maverick>
在web.config配置加入Maverick配置节:
<configSections>
<sectionGroup name="Maverick">
<section name="Dispatcher" type="System.Configuration.NameValueSectionHandler,system " />
</sectionGroup>
</configSections>
<Maverick>
<Dispatcher>
<add key="configFile" value="maverick.config" /> //Maverick文件位置
<add key="reloadCommand" value="reload" />//reloadCommand名字,用来放置重新加载
<add key="currentConfigCommand" value="currentConfig" /> //当前命令名字
<add key="limitTransformsParam" value="maxTransforms" />//最大外套数
</Dispatcher>
</Maverick>
NMav在应该也是一个比较早(2003就已经发布了1.1版)的一个.Net下的MVC实现,其实现是非常轻量的,而功能又是比较完备并体现出它的灵活行。如果我们反观一下NMav,NMav在Asp.Net下的局限也是实实在在的,可以说NMav只是Maverick从Java到.Net的一个翻版,并没有考虑到Asp.Net的实际情况,它没有考虑到Asp.Net事件驱动开发的特点以及.Net的运行机制,这样的结果是直接导致了Asp.net页面上的Server控件不能用,起因是NMav和Page类根本上冲突了,加入进来的修补措施也是很粗糙的,连对Model的支持都没有了,那这样的还比不上UIP了。
NMav代码的存放放组织不是很好,而且有些类并没有太大的用处,上面提到的currentConfig和reloadCommand等,但是NMav整体上来看实现还是相当漂亮的。