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。
一、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方法。