本文原是论坛帖子,讨论在此处: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 List
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