掷鸡蛋者
发表于: 2010/5/17 10:38 引用 回复 只看该作者 1# TOP
管理员
性别: 男
积分:52173
阅读权限:43385
帖子: 8318
加入时间: 2010/4/29
最后登录: 2019/8/17
总的流程分成两部分。

第一部分、包装 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<ProcessorBase> initProcessor() {
    List<ProcessorBase> list = new List<ProcessorBase>();
    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 
本帖于 2010/9/8 11:06:10 被 掷鸡蛋者 最后编辑
关键词 修改tag
而死,不默而生
power
发表于: 2010/5/17 14:10 引用 回复 只看该作者 2# TOP
江湖少侠
性别: 男
积分:383
阅读权限:170
帖子: 36
加入时间: 2010/5/6
最后登录: 2016/12/2

好啊,认真学习下。

haseebbser
发表于: 2010/5/17 15:07 引用 回复 只看该作者 3# TOP
江湖新秀
性别: 男
积分:328
阅读权限:142
帖子: 29
加入时间: 2010/5/11
最后登录: 2013/1/20
源代码我也看到这里了,但是对于在控制器里写的代码,就是看不懂(如何获取数据,如何找到对应视图,如何根据视图生成最终的html)
掷鸡蛋者
发表于: 2010/5/17 15:18 引用 回复 只看该作者 4# TOP
管理员
性别: 男
积分:52173
阅读权限:43385
帖子: 8318
加入时间: 2010/4/29
最后登录: 2019/8/17
源代码我也看到这里了,但是对于在控制器里写的代码,就是看不懂(如何获取数据,如何找到对应视图,如何根据视图生成最终的html)
haseebbser at 2010-5-17 15:07

原来这样啊。你不要纠结了,这是因为框架自动帮你做了,你只要知道一个控制器controller对应一个视图文件夹,比如ArticleController的视图在 Article 目录下,ArticleController的Index方法的视图文件是Article目录下的Index就行了。

框架的作用就是帮你自动完成这些,不用你去手工加载view视图模板。如果框架不能自动完成,不能提高生产效率,也就没有意义了。



而死,不默而生
talentzzrr
发表于: 2010/5/17 15:48 引用 回复 只看该作者 5# TOP
江湖新秀
性别: 男
积分:163
阅读权限:81
帖子: 14
加入时间: 2010/5/12
最后登录: 2011/12/31

可是作为开发人员这个正是我们注意的地方啊,

talentzzrr
发表于: 2010/5/17 15:50 引用 回复 只看该作者 6# TOP
江湖新秀
性别: 男
积分:163
阅读权限:81
帖子: 14
加入时间: 2010/5/12
最后登录: 2011/12/31

顺便问下,jquery异步访问的页面是怎么产生的啊,我知道和上面是一个道理,可是看不明白这里的东西,这心里有多么难受啊,我看了好几天代码。还是不清楚

掷鸡蛋者
发表于: 2010/5/17 15:58 引用 回复 只看该作者 7# TOP
管理员
性别: 男
积分:52173
阅读权限:43385
帖子: 8318
加入时间: 2010/4/29
最后登录: 2019/8/17

可是作为开发人员这个正是我们注意的地方啊,

talentzzrr at 2010-5-17 15:48

 如果你想再创建一个mvc框架,才需要了解如何根据controller和action加载视图吧;如果是二次开发,只要知道把view视图放到哪个目录就行

而死,不默而生
掷鸡蛋者
发表于: 2010/5/17 16:02 引用 回复 只看该作者 8# TOP
管理员
性别: 男
积分:52173
阅读权限:43385
帖子: 8318
加入时间: 2010/4/29
最后登录: 2019/8/17

顺便问下,jquery异步访问的页面是怎么产生的啊,我知道和上面是一个道理,可是看不明白这里的东西,这心里有多么难受啊,我看了好几天代码。还是不清楚

talentzzrr at 2010-5-17 15:50

 你指的是异步访问表单吧,虽然使用起来很简单,只要在html中加上一个 class="ajaxPostForm",但是背后的流程涉及到大量的js代码,在 wojilu.common.js 中。还是那句话,如果要再造一个 mvc+ajax 框架,你才需要了解这个,否则你这么用就行了呗

说老实话,写 js 还是很辛苦的。

而死,不默而生
ilwm1984
发表于: 2010/5/19 15:10 引用 回复 只看该作者 9# TOP
江湖新秀
性别: 男
积分:105
阅读权限:40
帖子: 6
加入时间: 2010/5/18
最后登录: 2011/10/22

这个流程初看很生涩,但是如果结合ASP.NET应用程序的生命周期来看,就脉络清晰了。
接下来就需要一步一步的剖析。
十分欣赏LZ对Filter的定义及使用方法。 不过,这个需要在Global.asax中声明处理。
是否可以提取出来,单独做一个Processor呢?

掷鸡蛋者
发表于: 2010/5/19 17:05 引用 回复 只看该作者 10# TOP
管理员
性别: 男
积分:52173
阅读权限:43385
帖子: 8318
加入时间: 2010/4/29
最后登录: 2019/8/17

这个流程初看很生涩,但是如果结合ASP.NET应用程序的生命周期来看,就脉络清晰了。
接下来就需要一步一步的剖析。
十分欣赏LZ对Filter的定义及使用方法。 不过,这个需要在Global.asax中声明处理。
是否可以提取出来,单独做一个Processor呢?

ilwm1984 at 2010-5-19 15:10

 兄弟看得很仔细,我再考虑一下,似乎是个不错的建议。

而死,不默而生

快速回复主题