转载请注明出处:http://blog.youkuaiyun.com/jh_zzz
这两天大致看了一下 KooBoo 的代码并做了笔记,时间有限,其中还有大量的代码没有来得及细看。
第一次运行时系统自动重定向到安装界面,之后根据用户的选择,启用相应的数据库以及对应的 web.config 文件。
1. MVC
a) Everest.CmsService.Web 以及 Everest.Library.Mvc 中的文件基本都是为了扩展 MVC 而设计的,首先 web.config 中 httpModules 配置了 XmlRoutesModule :
< add name = "XmlRoutesModule " type = "Everest.Library.Mvc.XmlRoutesModule,Everest.Library "/>
XmlRoutesModule 初始化时向 RouteTable .Routes 注册所有的路由表,具体是从根目录的 routes.config 中读取的。
b) 其次 web.config 中 httpModules 配置了 CmsControllerModule
< add name = "CmsControllerModule " type = "Everest.CmsServices.Web.CmsControllerModule,Everest.CmsServices "/>
CmsControllerModule 初始化时将修改 MVC 框架的 ControllerFactory 为 CmsControllerFactory :
ControllerBuilder .Current.SetControllerFactory(controllerFactory);
c) 页面加载时 CmsControllerFactory 的 CreateController 方法被调用,找到对应的 Controller ,并根据路由的定义执行相应的方法。
同样的, web.config 中 httpModules 配置了 EverestWebFormViewEngineModule ,他在加载时会将 ViewEngine 修改成 EverestWebFormViewEngine 。
页面渲染时, FindView 被执行,以管理员界面首页为例,页面为 ~/Views/Form/Index.aspx ,最终还是以 WebFormViewEngine 来进行渲染。
打开 Index.aspx ,有很多 Html.ExternalResources : <%= Html.ExternalResources("styles" , new { Media = "Screen, Print" })% , 具体引用的文件定义在 externalResources.config 中,根据指定的名称输出相应的 HTML ,输出的内容类似于这样:
<script src="/Kooboo_ExternalResource/Index?name=extjs&version=20100422&display=Show" type="text/javascript"></script>
这又导致新的 MVC 请求,这次是 ExternalResourceController 以及 ScriptController 处理,最终在页面上输出了相应的脚本,个人这个方法不错,页面简洁,重要的是可以灵活控制。
d) 对于管理站点,页面加载完成后, UI 基本由 ExtJS 创建, ExtJS 目前官方也提供了 ExtDesigner ,不过是收费的。
e) 关于 MVC 中的上下文, web.config 中 httpModules 配置了 KoobooUrlRoutingModule ,订阅了 PostResolveRequestCache 和 PostMapRequestHandler 两个事件,和标准 MVC 框架做法都是一样的,他的作用就是打包上下文,供后面使用。
f) Routes.config 中定义了 routeHandlerType 为 KoobooMvcRouteHandler ,他的 GetHttpHandler() 返回的是 KoobooMvcHandler ,并将重新将上下文打包传给他。
g) web.config 中 httpHandlers 中定义了 .mvc 的 httphandle 为 KoobooMvcHttpHandler ,用以处理 .mvc 的文件请求。
2. Application 运行
a) 以默认的 SmallBusiness Application 为例,当我们访问 http://website/c-SmallBusiness/Index 这样的站点时,根据 MVC 路由定义, CommonController 的 Excute 被调用,
public virtual ActionResult Execute()
{
Application = ((Everest.CmsServices.Web.KoobooHttpRequestWrapper )Request).CmsApplication;
b) K oobooHttpRequestWrapper.CmsApplcation 为 aspnet_Applications , web.config 中 httpModules 配置了 ApplicationInitializerModule ,会从数据库中读取 Application 列表并初始化所有 Application ,具体的工作在 ApplicationInitializer. InitializeGlobal 中完成,数据映射是用的 Entity Framework 。
c) 获取到 Application 后,首先 ExecutePluginsPreAction 执行页面插件的预处理 ,然后根据规则查询相应的内容数据放到上下文中,再找到对应的模板进行页面渲染,最后 ExecutePluginPostAction 执行页面插件的后处理。
d) CachedData .GetPageTemplate 从数据库中查询返回相应的 Cms_PageTemplate ,最终 ViewPath 中创建 VirtualPathViewResult 渲染相应的 aspx 页面。
e) 以 SmallBusiness 的 Index 为例,页面渲染时得到的模板为 SmallBusiness/ LayoutTemplate/home.aspx , home.aspx 除一般的内容外,还有像这样的控件:
< cms : Position ID ="home_banner" runat ="server" />
Position 加载时会执行 PositionHolder. LoadCmsControls() ,继续会调用 CachedData .GetContentTemplateInPage() 获取对应此 Position 控件所有的内容模板,这些由管理员创建站点时设置保存在数据中, AddContentTemplate 根据模板的 Guid 找到 ContentTemplate 目录下对应的 ascx 文件,然后用此创建页面上对应的 Control 。
f) 以 LeftSideBar.ProductCategory.ascx 为例,一般获取内容的语句像这样:
foreach (var category in this .GetContents("categories" ))
函数定义在 CmsViewExtensions.cs 中:
public static IEnumerable <IDictionary <string , object >> GetContents(this ICmsView cmsView, string viewDataKey)
{
var contents = cmsView.GetViewDataValue(viewDataKey);
return ContentExtension .ToList(contents);
}
实际是从 PrivateViewData 中取的,每个控件都是一个 CmsUserControl 实例, CmsUserControl 在 OnLoad 时会初始化 PrivateViewData 数据:
DataRuleEvaluator .Evaluate(CmsContext.DataRuleContext, CachedData .GetDataRulesByContentTemplate(ContentTemplate.UUID));
具体取数据的过程也是比较复杂的, Everest.CmsServices/DataRule/ 中的文件基本都是用来做这个事的。
g) 模板中还可以插入模块的内容,这个在 SmallBusiness 中默认没有体现,基本上模块就相当于一个小型的站点,具体可参考 PositionHolder 中的 AddModule 。
3. 资源
以 home.aspx 为例,需要支持自定义资源的地方如:
<%= this .GetResource("homepage.Title" , @"World class, custom widgets for your industry" )%>
对应于相应的 Application 的资源由 TextResourceService 的 GetTextResources() 从数据库中读取,并加到数据缓存中,然后根据相应的键值提取,如果找不到会自动添加到数据库中。
4. 缓存
a) 使用 Enterprise Library 的 Cache 方案。
b) CachedData 用以处理绝大部分读取数据缓存的操作。
c) Unity.config 中默认定义的 CacheProvider 为 EntlibCacheProvider ,可替换为其他缓存解决方案。
d) 此外异常捕获、日志、以及加密也都是使用 Enterprise Library 。