标签:
本文已同步到系列目录:OSharp快速开发框架解说系列
相对于OSharp 3.0,3.3版本最大的更新,就是从框架级别定义了初始化流程,对初始化功能进行了抽象与封装,不依赖于第三方实现,第三方实现仅作为可替换的服务实现方案存在。
例如,依赖注入功能中,接口与其实现类的映射配置,对象容器的构建,对象的解析获取,都将通过框架定义的API来完成,而Autofac,仅作为这些功能的实现方存在,如果不想使用Autofac,则可以很方便的切换成别的IoC组件。
具体的初始化功能是怎样抽象与定义的,我们将在后续文章中逐个进行详解,这里先从整体来看看整个初始化过程是怎样的。
OSharp框架在Web.Config(App.Config)配置文件的configSections节点中定义了类型为 OSharp.Core.Configs.ConfigFile.OSharpFrameworkSection 的配置信息,主要节点如下所示:
1 <osharp xmlns="http://file.osharp.org/schemas/osharp.xsd"> 2 <data> 3 <contexts> 4 <context name="default" enabled="true" dataLoggingEnabled="true" connectionStringName="default" 5 type="OSharp.Core.Data.Entity.DefaultDbContext, OSharp.Core.Data.Entity"> 6 <initializer type="OSharp.Core.Data.Entity.DefaultDbContextInitializer, OSharp.Core.Data.Entity" 7 mapperFiles="OSharp.Demo.Core"> 8 <createInitializer type="OSharp.Demo.Data.CreateDatabaseIfNotExistsWithSeed,OSharp.Demo.Core" /> 9 </initializer> 10 </context> 11 <context name="logging" enabled="true" dataLoggingEnabled="false" connectionStringName="default" 12 type="OSharp.Core.Data.Entity.Logging.LoggingDbContext, OSharp.Core.Data.Entity"> 13 <initializer type="OSharp.Core.Data.Entity.Logging.LoggingDbContextInitializer, OSharp.Core.Data.Entity" 14 mapperFiles="OSharp.Core.Data.Entity" /> 15 </context> 16 </contexts> 17 </data> 18 <logging> 19 <entry enabled="true" level="Debug" /> 20 <basic> 21 <adapters> 22 <adapter name="log4net" enabled="true" 23 type="OSharp.Logging.Log4Net.Log4NetLoggerAdapter, OSharp.Logging.Log4Net" /> 24 </adapters> 25 </basic> 26 </logging> 27 </osharp>
使用的时候,需要在configSections节点中增加名为“osharp”的节点信息:
1 <section name="osharp" type="OSharp.Core.Configs.ConfigFile.OSharpFrameworkSection, OSharp.Core" />
通过以上配置,系统初始化之后,就能通过 OSharpConfig.Instance 这个单例来获取OSharpConfig的配置信息供框架初始化的时候使用。
OSharp的依赖注入功能,是参考ASP.NET 5 中的 Microsoft.Framework.DependencyInjection.Abstractions 来设计完成的,依赖注入架构的思路,也参考了 ASP.NET 5 的“一切皆服务”的架构思想。首先收集所有系统中各个模块中需要使用到的注入点、接口与实现类的映射等信息,封装成描述服务映射信息的 ServiceDescriptor ,并构建成映射信息的集合 IServiceCollection ,然后后面的依赖注入容器的构建,将以这个映射信息集合为基础进行构建。
参照传统,对于依赖注入对象的生命周期描述,OSharp中定义了实时模式的(Transient)、局部模式的(Scoped)、单例模式的(Singleton)三种生命周期,为了方便构建服务与服务实现之间的映射关系,同时定义了 ITransientDependency 、 IScopeDependency 、 ISingletonDependency 三个空接口来标注映射的生命周期类型。在系统初始化的时候,只需要遍历程序集中的所有类型,查找所有这三个空接口的实现类型,即可很方便的构建服务与服务实现的映射描述的 ServiceDescriptor 对象。
自动构建映射关系,只需要如下2行代码即可完成:
1 IServicesBuilder builder = new ServicesBuilder(new ServiceBuildOptions()); 2 IServiceCollection services = builder.Build();
大部分映射关系,可以使用上面所说的三个接口来标注进行创建,但对于部分特殊的映射类型,或者某些需要后期来决定是否启用的模块,不利于使用自动检索程序集构建的映射关系,可通过在各个模块中构建,然后手动添加到 IServiceCollection 中来进行创建:
1 services.AddLog4NetServices(); //添加log4net的日志模块服务 2 services.AddDataServices(); //添加数据访问模块的服务
这样,只需要简单的操作,我们即可将系统中所有的服务与服务实现的映射信息提取出来。
平台初始化功能,主要是通过 FrameworkInitializer 初始化类来完成的。主要做的工作有以下几点:
FrameworkInitializer 类型实现如下:
1 /// <summary> 2 /// 框架初始化 3 /// </summary> 4 public class FrameworkInitializer : IFrameworkInitializer 5 { 6 //基础模块,只初始化一次 7 private static bool _basicLoggingInitialized; 8 private static bool _databaseInitialized; 9 private static bool _entityInfoInitialized; 10 11 /// <summary> 12 /// 开始执行框架初始化 13 /// </summary> 14 /// <param name="services">服务映射集合</param> 15 /// <param name="iocBuilder">依赖注入构建器</param> 16 public void Initialize(IServiceCollection services, IIocBuilder iocBuilder) 17 { 18 services.CheckNotNull("services"); 19 iocBuilder.CheckNotNull("iocBuilder"); 20 21 OSharpConfig config = OSharpConfig.Instance; 22 23 //使用副本进行初始化,防止不同平台间的相互污染 24 IServiceCollection newServices = services.Clone(); 25 //依赖注入初始化 26 IServiceProvider provider = iocBuilder.Build(newServices); 27 28 //日志功能初始化 29 IBasicLoggingInitializer loggingInitializer = provider.GetService<IBasicLoggingInitializer>(); 30 if (!_basicLoggingInitialized && loggingInitializer != null) 31 { 32 loggingInitializer.Initialize(config.LoggingConfig); 33 _basicLoggingInitialized = true; 34 } 35 36 //数据库初始化 37 IDatabaseInitializer databaseInitializer = provider.GetService<IDatabaseInitializer>(); 38 if (!_databaseInitialized) 39 { 40 if (databaseInitializer == null) 41 { 42 throw new InvalidOperationException(Resources.FrameworkInitializerBase_DatabaseInitializeIsNull); 43 } 44 databaseInitializer.Initialize(config.DataConfig); 45 _databaseInitialized = true; 46 } 47 48 //实体信息初始化 49 if (!_entityInfoInitialized) 50 { 51 IEntityInfoHandler entityInfoHandler = provider.GetService<IEntityInfoHandler>(); 52 if (entityInfoHandler == null) 53 { 54 throw new InvalidOperationException(Resources.FrameworkInitializerBase_EntityInfoHandlerIsNull); 55 } 56 entityInfoHandler.Initialize(); 57 _entityInfoInitialized = true; 58 } 59 //功能信息初始化 60 IFunctionHandler functionHandler = provider.GetService<IFunctionHandler>(); 61 if (functionHandler == null) 62 { 63 throw new InvalidOperationException(Resources.FrameworkInitializerBase_FunctionHandlerIsNull); 64 } 65 functionHandler.Initialize(); 66 } 67 }
平台初始化步骤:
值得注意的是,对于Mvc/WebApi/SignalR三个不同平台的初始化,所使用的服务映射信息集合 IServiceCollection 是同一个集合,为了隔离不同平台,避免相互之间造成类型污染,在将集合传入 IIocBuilder 的时候,使用的是Clone之后的集合的副本,而非集合本身,如上第24行所示。
有了这个初始化实现,我们使用初始化功能的时候,只需执行如下几行代码即可:
1 IFrameworkInitializer initializer = new FrameworkInitializer(); 2 3 initializer.Initialize(services, new MvcAutofacIocBuilder()); 4 initializer.Initialize(services, new WebApiAutofacIocBuilder()); 5 initializer.Initialize(services, new SignalRAutofacIocBuilder());
整个框架的初始化代码,如下所示,我们只需要在Global的Application_Start方法中执行如下代码,即可完成框架初始化:
1 IServicesBuilder builder = new ServicesBuilder(new ServiceBuildOptions()); 2 IServiceCollection services = builder.Build(); 3 services.AddLog4NetServices(); 4 services.AddDataServices(); 5 6 IFrameworkInitializer initializer = new FrameworkInitializer(); 7 8 initializer.Initialize(services, new MvcAutofacIocBuilder()); 9 initializer.Initialize(services, new WebApiAutofacIocBuilder()); 10 initializer.Initialize(services, new SignalRAutofacIocBuilder());
框架中还提供了基于Owin的初始化方式,执行代码如下所示,主要是通过三个 IAppBuilder 的扩展方法来完成的:
1 public partial class Startup 2 { 3 public void Configuration(IAppBuilder app) 4 { 5 // 有关如何配置应用程序的详细信息,请访问 http://go.microsoft.com/fwlink/?LinkID=316888 6 7 IServicesBuilder builder = new ServicesBuilder(new ServiceBuildOptions()); 8 IServiceCollection services = builder.Build(); 9 services.AddLog4NetServices(); 10 services.AddDataServices(); 11 12 app.UseOsharpMvc(services, new MvcAutofacIocBuilder()); 13 app.UseOsharpWebApi(services, new WebApiAutofacIocBuilder()); 14 app.UseOsharpSignalR(services, new SignalRAutofacIocBuilder()); 15 16 ConfigurationWebApi(app); 17 ConfigureSignalR(app); 18 } 19 }
本篇仅是简单的介绍下OSharp框架的初始化流程,具体的每个环节的设计细节,将在后续的几篇文章中进行详解。
OSharp项目已在github.com上开源,地址为:https://github.com/i66soft/osharp,欢迎阅读代码,欢迎 Watch(关注),欢迎 Star(推荐),如果您认同 OSharp 项目的设计思想,欢迎参与 OSharp 项目的开发。
在Visual Studio 2013中,可直接获取 OSharp 的最新源代码,获取方式如下,地址为:https://github.com/i66soft/osharp.git
很多童鞋想参与开源项目,为项目做贡献,但又不知道如何做,这里我简单说下参与OSharp的步骤吧:
OSharp的相关类库已经发布到nuget上,欢迎试用,直接在nuget上搜索 “osharp” 关键字即可找到
本文已同步到系列目录:OSharp快速开发框架解说系列
【开源】OSharp3.3框架解说系列(7.1):初始化流程概述
标签:
原文地址:http://www.cnblogs.com/guomingfeng/p/osharp-initialize-overall.html