词条统计
浏览次数:5682 次
编辑次数:4次 历史版本
最近更新:2013/6/20
创建者:掷鸡蛋者

本文原是论坛帖子,讨论在此处:http://www.wojilu.com/Forum1/Topic/80 


总的流程分成两部分。

第一部分、包装 MvcContext

在 wojilu.Web.Mvc.CoreHandler 中,根据HttpContext,生成经过包装过的MvcContext(详细说明见此处:http://www.wojilu.com/Forum1/Topic/58 )。这个很简单。


第二部分,开始 mvc 的解析

整个 mvc 的解析流程(生命周期),是由 ProcessContext 控制的,请看它启动(Begin方法)的代码,依次装载了11个处理器(processor)



而这11个processor,就是 wojilu mvc 的整个解析流程。下面通过代码注释的办法,解释一下这11个processor的职责:

private static ListinitProcessor() {
    Listlist = new List();
    list.Add( new RouteProcessor() );              // 根据url解析路由
    list.Add( new InitContextProcessor() );      // 初始化 "上下文" 相关数据(包括初始化当前controller)
    list.Add( new ActionMethodChecker() );     // 检查当前请求的方法(action)是否存在
    list.Add( new ForbiddenActionChecker() ); // 检查当前action是否禁止访问
    list.Add( new LoginActionChecker() );        // 检查当前action是否需要登录才能访问
    list.Add( new HttpMethodChecker() );        // 检查当前http方法是否正确
    list.Add( new PermissionChecker() );         // 重要:依次检查各级namespace是否做了权限控制
    list.Add( new ActionProcessor() );             // 关键:执行当前action,将controller的数据和view(视图模板)结合
    list.Add( new LayoutProcessor() );            // 根据当前action的结果,再加上当前controller的布局(layout)内容
    list.Add( new NsLayoutProcessor() );        // 再加上各级namespace的布局内容
    list.Add( new RenderProcessor() );           // 将最终结果呈现给客户端
    return list;
}


其中每一个 processor 执行之前,都引发 MvcEvent 事件,你可以自定义事件过滤器,在每一个processor执行之前,过滤每一个 processor。
换句话说,每一个 processor 都是可以扩展的。下图就是一个mvc过滤器的实现(详见:http://www.wojilu.com/Common/Page/48 ):



下面依次解释比较重要的几个 processor。

第一,路由(route)解析。在 RouteProcessor 中完成。route解析完成之后,会将结果放入 MvcContext 中,其中的路由数据,主要是

ctx.route.id当前ID(整数)
ctx.route.controller当前控制器(字符串)
ctx.route.action当前控制器的方法(字符串)
ctx.route.owner被访问对象(字符串)
ctx.route.ownerType被访问对象的类型(site/group/user等)(字符串)
ctx.route.appId当前应用程序的appId(有时候可以为0)(整数)
ctx.route.page当前页面(在翻页的时候出现)(整数)
ctx.route.query当前url中的查询字符串(QueryString)(字符串)


第二,初始化上下文。 InitContextProcessor,它又分成6个部分。

initor.InitViewer( ctx ); // 初始化当前登录用户(访问者) 
initor.InitOwner( ctx ); // 初始化当前被访问对象(site或group或user)
initor.InitController( ctx ); // 初始化控制器
initor.InitPermission( ctx ); // 初始化权限检查(用处不大)

IList paths = PathHelper.GetPathList( ctx.route.getRootNamespace(), ctx.controller.GetType().Namespace );
ctx.utils.setLayoutPath( paths );
OnlineManager.Refresh( ctx ); // 刷新当前在线用户
initor.InitApp( ctx ); // 初始化当前app


对于“上下文初始化器(ContextInit)”,框架自带一个默认的。对于简单的系统来说就够了。但对于“我记录网站综合系统”这样比较复杂的应用来说,就需要自定义。

自定义的“上下文初始化器”必须继承自 ContextInitBase,你可以看“我记录网站综合系统”中的 wojilu.Web.Context.ContextInit 是如何实现的(在wojilu.core项目中) ,其中关键是初始化当前登录用户被访问对象,这两个对象是“我记录网站综合系统”的用户系统的核心概念,详解见此处:http://www.wojilu.com/Forum1/Topic/62

第三、检查各级权限

wojilu MVC framework在执行某控制器之前,会先从根命名空间开始,一级一级的检查,检查每个命名空间下是否有 SecurityController 这个控制器,如果有,就执行它的 CheckPermission 方法。而您可以在 CheckPermission 方法中,判断用户的权限。如果检查未通过,您可以使用 echo/ctx.applicationComplete 等方法终止程序的运行。
更多说明和示例见:http://www.wojilu.com/Common/Page/33  


第四、运行 controller 的 action 方法

这是整个mvc流程的核心。作用就是将数据和视图模板(view)结合。它也提供了扩展点,通过实现 IActionFilter 接口,你可以在action被执行之前或之后插入自定义的程序逻辑:


比如系统自带的数据库事务批注(attribute),就是一个action filter:


另外还有一个action缓存批注(attribute),也是同理实现的。

第五、加上各级布局

布局(layoute)相当于ASP.NET 中的 master page(母版页),但是可以根据namespace逐级增加,也可以手动隐藏。layout给系统提供了一个一致性呈现的效果。更多解释和示例见: http://www.wojilu.com/Common/Page/12