Oxite分析之Module

change set:42353

download :http://oxite.codeplex.com/SourceControl/ListDownloadableCommits.aspx

 

约定:在Oxite中,对实现了IOxiteModule接口的类称之为Module或模块。

在某种角度上,可以将Oxite看成是由一个个Module构成的。Oxite项目Modules目录下的各个Module可以看做是系统模块,如Oxite.Modules.Core.OxiteModule、Oxite.Modules.Membership.MembershipModule等;而解决方案目录Modules下的各个Module可以看做是自定义Module,如Oxite.Blogs.BlogsModule、Oxite.CMS.CMSModule。

JIX]6V28HQMV)NAM$UQB2NB

 

一、IOxiteModule接口

每个Module都实现了IOxiteModule接口,下面看看IOxiteModule接口的定义:

 1:  public interface IOxiteModule
 2:   {
 3:      void Initialize();
 4:      void Unload();
 5:      void RegisterRoutes(RouteCollection routes);
 6:      void RegisterCatchAllRoutes(RouteCollection routes);
 7:      void RegisterFilters(IFilterRegistry filterRegistry);
 8:      void RegisterModelBinders(ModelBinderDictionary modelBinders);
 9:      void RegisterWithContainer();
10:  }

由于目前Oxite官方文档几乎空白,而且又没正式发布,各个方法的作用分别是猜测如下:

RegisterWithContainer:向依赖注入容器注册Module所需的对象或实例;
Initialize:初始化Module(OxiteModule类和PluginsModule类)
RegisterFilters:注册自定义ActionFilter
RegisterModelBinders:注册自定义ModelBinders
RegisterRoutes:设置路由规则
RegisterCatchAllRoutes:作用未知

在“Oxite分析之初始化”一文中曾提到过,当Oxite初始化时,将会调用各个被加载的Module的除了Unload方法外的所有方法。而Unload方法将在Application_End方法中被间接调用用于清理一些资源。

具体查看LoadModules : IBootStrapperTask类的Execute方法:

 1:  OxiteConfigurationSection config = container.Resolve<OxiteConfigurationSection>();
 2:  IModulesLoaded modulesLoaded = this.container.Resolve<IModulesLoaded>();
 3:  RouteCollection routes = this.container.Resolve<RouteCollection>();
 4:  IFilterRegistry filterRegistry = this.container.Resolve<FilterRegistry>();
 5:  ModelBinderDictionary modelBinders = this.container.Resolve<ModelBinderDictionary>();
 6:  //...
 7:   
 8:   filterRegistry.Clear();
 9:   
10:  modelBinders.Clear();
11:   
12:  //todo: (nheskew) get plugin routes registered on load in the right order instead of just clearing the routes before module init
13:   routes.Clear();
14:   
15:  foreach (OxiteModuleConfigurationElement module in config.Modules)
16:  {
17:      IOxiteModule moduleInstance = modulesLoaded.Load(config, module);
18:   
19:      if (moduleInstance != null)
20:      {
21:          moduleInstance.RegisterWithContainer();
22:          moduleInstance.Initialize();
23:          moduleInstance.RegisterFilters(filterRegistry);
24:          moduleInstance.RegisterModelBinders(modelBinders);
25:   
26:          this.container.RegisterInstance(modulesLoaded);
27:   
28:          //...
29:      }
30:  }
31:   
32:  routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
33:   
34:  routes.LoadFromModules(modulesLoaded);
35:   
36:  routes.LoadCatchAllFromModules(modulesLoaded);
37:   

 

这里需要注意各个方法的调用顺序,这一点可以查看PluginsModule的源码。我们一般会认为Initialize应该被最先调用,但PluginsModule类的Initialize方法将会用到RegisterWithContainer方法中进行的某些配置,所以RegisterWithContainer方法应该最新被调用。

二、IOxiteDataProvider

Module不一定要实现IOxiteDataProvider。当需要制定Module内部数据访问方式时,通过外部配置以及让Module实现IOxiteDataProvider可以达到。
另外,Oxite配置的灵活性使得Module也可以不实现IOxiteDataProvider接口,而新建一个类来实现。目前Oxite版本中实现在了Module本身中。
通过这样的配置,使得各个Module可以拥有自己特有的数据访问方式,甚至于每个Module可以放在不同的数据库或不同类型的数据库中。在数据访问上说,去除了与系统本身的耦合。

在“Oxite分析之初始化”一文中曾提到过web.config配置文件的自定义"oxite"配置节点。具体配置已经移至单独的Oxite.config,下面看看它的内容:

 1:  <oxite>
 2:    <connectionStrings>
 3:      <add name="Sql" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=Oxite.Database;Integrated Security=true;"/>
 4:      <!--<add name="Sql" connectionString="Data Source=.\SQLEXPRESS;AttachDBFileName=|DataDirectory|Oxite.Database.mdf;Integrated Security=true;User Instance=true;"/>-->
 5:    </connectionStrings>
 6:    <dataProviders defaultConnectionString="Sql">
 7:      <add name="Membership" type="Oxite.Modules.Membership.MembershipModule, Oxite" category="LinqToSql" />
 8:      <add name="Tags" type="Oxite.Modules.Tags.TagsModule, Oxite" category="LinqToSql" />
 9:      <add name="Comments" type="Oxite.Modules.Comments.CommentsModule, Oxite" category="LinqToSql" />
10:      <add name="Plugins" type="Oxite.Modules.Plugins.PluginsModule, Oxite" category="LinqToSql" />
11:      <add name="Blogs" type="Oxite.Modules.Blogs.BlogsModule, Oxite.Blogs" category="LinqToSql" />
12:      <add name="CMS" type="Oxite.Modules.CMS.CMSModule, Oxite.CMS" category="LinqToSql" />
13:      <add name="Conferences" type="Oxite.Modules.Conferences.ConferencesModule, Oxite.Conferences" category="LinqToSql" />
14:      <add name="Search" type="Oxite.Modules.Search.SearchModule, Oxite" category="LinqToSql" />
15:    </dataProviders>
16:    <modules>
17:      <add name="AspNetCache" type="Oxite.Modules.AspNetCache.AspNetCacheModule, Oxite" />
18:      <add name="Membership" type="Oxite.Modules.Membership.MembershipModule, Oxite" dataProvider="Membership" />
19:      <add name="FormsAuthentication" type="Oxite.Modules.FormsAuthentication.FormsAuthenticationModule, Oxite" />
20:      <add name="Core" type="Oxite.Modules.Core.OxiteModule, Oxite" />
21:      <add name="Tags" type="Oxite.Modules.Tags.TagsModule, Oxite" dataProvider="Tags" />
22:      <add name="Files" type="Oxite.Modules.Files.FilesModule, Oxite" />
23:      <add name="Comments" type="Oxite.Modules.Comments.CommentsModule, Oxite" dataProvider="Comments" />
24:      <add name="Plugins" type="Oxite.Modules.Plugins.PluginsModule, Oxite" dataProvider="Plugins" />
25:      <add name="Blogs" type="Oxite.Modules.Blogs.BlogsModule, Oxite.Blogs" dataProvider="Blogs" />
26:      <add name="CMS" type="Oxite.Modules.CMS.CMSModule, Oxite.CMS" dataProvider="CMS" />
27:      <add name="Conferences" type="Oxite.Modules.Conferences.ConferencesModule, Oxite.Conferences" dataProvider="Conferences" enabled="false" />
28:      <add name="Search" type="Oxite.Modules.Search.SearchModule, Oxite" dataProvider="Search" />
29:      <add name="Site" type="OxiteSite.App_Code.Modules.OxiteSite.OxiteSiteModule" />
30:    </modules>
31:  </oxite>

modules节点下的元素,有的具有dataProvider属性(查看OxiteModuleConfigurationElement类的DataProvider属性的定义)。比如name为"Search"的元素,dataProvider为"Search":

1:      <add name="Search" type="Oxite.Modules.Search.SearchModule, Oxite" dataProvider="Search" />  

其对应的是dataProviders节点下的name为"Search"的元素:

1:      <add name="Search" type="Oxite.Modules.Search.SearchModule, Oxite" category="LinqToSql" />  

 

接着请看ModulesLoaded类的Load方法:

 1:  public IOxiteModule Load(OxiteConfigurationSection config, OxiteModuleConfigurationElement module)
 2:  {
 3:      if (module == null || !module.Enabled) return null;
 4:   
 5:      foreach (OxiteDataProviderConfigurationElement dataProvider in config.Providers)
 6:      {
 7:          if (dataProvider.Name == module.DataProvider)
 8:          {
 9:              Type dataProviderType = Type.GetType(dataProvider.Type);
10:   
11:              if (dataProviderType == null)
12:                  throw new TypeLoadException(string.Format("Could not load type '{0}'.", dataProvider.Type));
13:   
14:              IOxiteDataProvider dataProviderInstance = container.Resolve(dataProviderType) as IOxiteDataProvider;
15:   
16:              if (dataProviderInstance != null)
17:                  dataProviderInstance.ConfigureProvider(config, dataProvider, container);
18:   
19:              break;
20:          }
21:      }
22:   
23:      //…
25: }

OxiteConfigurationSection config为整个oxite配置节点;OxiteModuleConfigurationElement module为oxite配置节点modules下的一个元素(比如name为"Search"的元素)
上述代码的第5行开始,遍历oxite.config配置中的dataProviders节点下的dataProvider元素,如果元素的name值等于module的dataProvider属性,通过dataProvider元素的type属性,获取类型。接着判断类型是否真的继承于IOxiteDataProvier。如果是,调用类型的ConfigureProvider方法。

posted @ 2009-09-08 00:16  alby  阅读(2907)  评论(4编辑  收藏  举报