1、 ABP Framework 入门开发指南 领域驱动设计 (DDD)红宝书 修订版本号:1.0.0.0 ABP 框架中国小组(ABPFrameWorkGroup) 版权所有 2015-06-11 ABP Framework 入门开发指南 ABP 框架中国小组(ABPFrameWorkGroup) 版权所有 | 版本:1.0 序 言 天道 该开发指南基于 ABP Framework 官方文档,由 ABP 框架中国小组 (ABPFrameWorkGroup)翻译。ABP 框架中国小组在 Github 的地址为: 讨论。 以后,最新的 ABPFrameWork 档,ABPFrameWork 实例教程
2、,以及代码都通过 Github 的 ABP 框架中国小组(ABPFrameWorkGroup)发布,请大家关注。 ABP 官方文档翻译征集启动以来,得到了大家的热烈响应,先后共有 10 多名群友参与了 翻译,目前翻译工作已经安排完毕,再次感谢广大群友的热烈支持。毫无疑问,该开发指南的 发布是一次团体智慧和协作的结晶,是”ABP 框架中国小组”共同努力的成果。我们应当感谢他 们的默默付出,感谢他们在这个酷热的夏天依旧能够挥洒着汗水辛苦的工作。 此次的翻译工作完全是个人自主行为,旨在帮助那些学习.NET 架构和研究领域驱动设计 (DDD)的开发者们。我们有理由相信,通过学习官方文档并结合 ABP
3、的源码,大家的.NET 水 平必定有所提高。 该文档不仅是 ABP 的开发指南,也是.NET 架构设计的一个优秀参考范本,指南中提及的 各种封装和技术实现,也可以很方便的集成到自己的项目中去。因此,这里推荐大家在研究源 码的时候,遇到问题可以首先参考一下这本指南。 关于此次翻译的标准如下: (1) 保留了原文的大部分关键词,这样方便大家以后学习这些常见词汇。 (2) 翻译的人称有第一人称和第二人称,由于时间关系,来不及统一。我个人倾向于第一 人称,因此对部分群友的翻译做了调整。 (3) 对部分翻译的语法做了调整,并且更加符合中国人的习惯。 (4) 翻译总体上保留了原文的风格,大家可以对比一下原
4、文,这不失为一个学习英语的最 佳实践。 (5) 对于常见词汇,翻译统一了标准:如,derived 翻译为派生,be used to 翻译为“调用” 而不是“被用来”,implement 翻译为实现,等等。这里不在叙述。 ABP Framework 入门开发指南 ABP 框架中国小组(ABPFrameWorkGroup) 版权所有 | 版本:1.0 关于 ABP 快速开发框架及实战: (1) 接下来 ABP 群会推出实例演示视频以及在线培训等。 (2)此外会根据大家的使用情况推出集成权限、用户、角色的基本开发框架。 (3)针对企业的开发者,我们将会推出高级版开发框架。 欢迎大家关注群主(上海 -
5、阳铭)的博客: ABP 架构设计交流群:134710707 ABP 框架中国小组(ABPFrameWorkGroup)成员如下(排名不分先后,随机排列): 山东-李伟 303283209 台灣-小張 2987853943 厦门-浩歌 385650059 深圳-Carl 280141563 冰封 121087772 NoZero 3921342 南京-菜刀 252900664 深圳-Leo 254213048 成都-乐忧 68336713 上海-半冷 562758404 上海-阳铭 614573519 东莞-天道 1832339824 总排版:北京-北北 34665992 总审核:上海-阳铭 6
6、14573519 总编辑:东莞-天道 1832339824 由于个人技术水平和英文水平也是有限的,因此错误在所难免。希望大家多多指正。有错 误或其他疑问的,请联系天道:1832339824 东莞-天道 于 2015 年 6 月 13 日星期六晚 20 点 ABP Framework 入门开发指南 ABP 框架中国小组(ABPFrameWorkGroup) 版权所有 | 版本:1.0 ABP Framework 入门开发指南 ABP 框架中国小组(ABPFrameWorkGroup) 版权所有 | 版本:1.0 i 目 录 1 ABP 总体介绍 .1 1.1 入门介绍 .1 1.1.1 ABP
7、采用了以下技术 .2 1.1.2 ABP 框架已实现了以下特性 2 1.1.3 ABP 适用的场景 4 1.2 多层架构体系 .4 1.2.1 前言 4 1.2.2 ABP 的体系结构 5 1.2.3 领域层 .5 1.2.4 应用层 .6 1.2.5 基础设施层 .6 1.2.6 WEB 与展现层 .6 1.2.7 其它 7 1.3 模块系统 .7 1.3.1 ABP 模块系统简介 7 1.3.2 生命期事件 .8 1.3.3 模块依赖 .9 1.3.4 自定义的模块方法 .10 1.4 启动配置 .11 1.4.1 配置 ABP 11 ABP Framework 入门开发指南 ABP 框架
8、中国小组 (ABPFrameWorkGroup) 版权所有 | 版本:1.0 ii 1.4.2 配置模块 .13 1.4.3 为一个模块创建配置 .13 2 ABP 公共结构 .16 2.1 ABP 依赖注入 .16 2.1.1 传统方式的问题 16 2.1.2 解决方案 .18 2.1.3 依赖注入框架 20 2.1.4 ABP 依赖注入的基础结构 21 2.1.5 附件 25 2.2 ABP 会话管理 .26 2.2.1 简介 26 2.2.2 注入会话 .27 2.2.3 使用会话属性 27 2.3 ABP 日志管理 .28 2.3.1 服务器端 .28 2.3.2 客户端 .32 2.
9、4 ABP 设置管理 .32 2.4.1 介绍 32 2.4.2 定义设置 .33 2.4.3 设置范围 .34 2.4.4 获取设置值 .35 ABP Framework 入门开发指南 ABP 框架中国小组(ABPFrameWorkGroup) 版权所有 | 版本:1.0 iii 2.4.5 更改设置 .36 2.4.6 关于缓存 .36 3 ABP 领域层 .37 3.1 ABP 领域层 实体 37 3.1.1 实体类 .37 3.1.2 接口约定 .38 3.1.3 IEntity 接口 41 3.2 ABP 领域层 仓储 42 3.2.1 IRepository 接口 42 3.2.2
10、 仓储的实现 .47 3.2.3 管理数据库连接 48 3.2.4 仓储的生命周期 48 3.2.5 仓储的最佳实践 48 3.3 ABP 领域层 工作单元 .49 3.3.1 通用连接和事务管理方法 49 3.3.2 ABP 的连接和事务管理 .50 3.3.3 工作单元 .53 3.3.4 选项 56 3.3.5 方法 57 3.3.6 事件 57 3.4 ABP 领域层 数据过滤器 .58 ABP Framework 入门开发指南 ABP 框架中国小组(ABPFrameWorkGroup) 版权所有 | 版本:1.0 iv 3.4.1 介绍 58 3.4.2 预定义过滤器 58 3.4.
11、3 禁用过滤器 .60 3.4.4 启用过滤器 .61 3.4.5 设定过滤器参数 62 3.4.6 自定义过滤器 62 3.4.7 其它对象关系映射工具 .64 3.5 ABP 领域层 领域事件 .64 3.5.1 事件总线 .64 3.5.2 定义事件 .65 3.5.3 触发事件 .65 3.5.4 事件处理 .66 3.5.5 注册处理器 .68 3.5.6 取消注册事件 69 4 ABP 应用层 .71 4.1 ABP 应用层 应用服务 .71 4.1.1 IApplicationService 接口 .71 4.1.2 应用服务类型 73 4.1.3 工作单元 .74 4.1.4
12、应用服务的生命周期 .76 4.2 ABP 应用层 数据传输对象 .76 ABP Framework 入门开发指南 ABP 框架中国小组(ABPFrameWorkGroup) 版权所有 | 版本:1.0 v 4.2.1 数据传输对象的作用 .76 4.2.2 DTO 约定 /这行代码的写法基本上是不变的。它的作用是把当前程序集的特定类或接口注册到依赖注入容器中。 ABP 框架会扫描所有的程序集,并且发现 AbpModule 类中所有已经导入的类,如果你 已经创建了包含多个程序集的应用,对于 ABP,我们的建议是为每一个程序集创建一个 Module(模块)。 1.3.2 生命期事件 在一个应用中
13、,ABP 框架调用了 Module 模块的一些指定的方法来进行启动和关闭模块 的操作。我们可以重载这些方法来完成我们自己的任务。 ABP 框架通过依赖关系的顺序来调用这些方法,假如:模块 A 依赖于模块 B,那么模块 B 要在模块 A 之前初始化,模块启动的方法顺序如下: 1) PreInitialize-B 2) PreInitialize-A 3) Initialize-B 4) Initialize-A 5) PostInitialize-B ABP Framework 入门开发指南 ABP 框架中国小组(ABPFrameWorkGroup) 版权所有 | 版本:1.0 9 6) Pos
14、tInitialize-A 下面是具体方法的说明: PreInitialize 预初始化:当应用启动后,第一次会调用这个方法。在依赖注入注册之前,你可以在这 个方法中指定自己的特别代码。举个例子吧:假如你创建了一个传统的登记类,那么你要先 注册这个类(使用 IocManager 对登记类进行注册),你可以注册事件到 IOC 容器。等。 Initialize 初始化:在这个方法中一般是来进行依赖注入的注册,一般我们通过 IocManager.RegisterAssemblyByConvention 这个方法来实现。如果你想实现自定义的依赖 注入,那么请参考依赖注入的相关文档。 PostIniti
15、alize 提交初始化:最后一个方法,这个方法用来解析依赖关系。 Shutdown 关闭:当应用关闭以后,这个方法被调用。 1.3.3 模块依赖 Abp 框架会自动解析模块之间的依赖关系,但是我们还是建议你通过重载 GetDependencies 方法来明确的声明依赖关系。 DependsOn(typeof(MyBlogCoreModule)/通过注解来定义依赖关系 public class MyBlogApplicationModule : AbpModule public override void Initialize() IocManager.RegisterAssemblyByCon
16、vention(Assembly.GetExecutingAssembly(); 例如上面的代码,我们就声明了 MyBlogApplicationModule 和 MyBlogCoreModule 的依 赖关系(通过属性 attribute),MyBlogApplicationModule 这个应用模块依赖于 MyBlogCoreModule 核心模块,并且,MyBlogCoreModule 核心模块会在 ABP Framework 入门开发指南 ABP 框架中国小组(ABPFrameWorkGroup) 版权所有 | 版本:1.0 10 MyBlogApplicationModule 模块之
17、前进行初始化。 1.3.4 自定义的模块方法 我们自己定义的模块中可能有方法被其他依赖于当前模块的模块调用,下面的例子,假 设模块 2 依赖于模块 1,并且想在预初始化的时候调用模块 1 的方法。这样,就把模块 1 注 入到了模块 2,因此,模块 2 就能调用模块 1 的方法了。 阳铭注: ABP 的模块系统与 Orchard 的模块有类似之处,但还是有比较大的差别。Orchard 的框架修改了 ASP.NET 程序集的默认加载方式(模块的 DLL 没有放在 Bin 文件夹下,是放在 WEB 项目根文件夹下面的 Modules 文件夹下),实现了功能模块的热插拔,而 ABP 的模块程序集还是放
18、在 Bin 文件夹下的,没有实 现热插拔。 public class MyModule1 : AbpModule public override void Initialize() /初始化模块 IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly();/这里, 进行依赖注入的注册。 public void MyModuleMethod1() /这里写自定义的方法。 DependsOn(typeof(MyModule1) public class MyModule2 : AbpModule private r
19、eadonly MyModule1 _myModule1; ABP Framework 入门开发指南 ABP 框架中国小组(ABPFrameWorkGroup) 版权所有 | 版本:1.0 11 public MyModule2(MyModule1 myModule1) _myModule1 = myModule1; public override void PreInitialize() _myModule1.MyModuleMethod1(); /调用 MyModuleMethod1 的方法。 public override void Initialize() IocManager.Reg
20、isterAssemblyByConvention(Assembly.GetExecutingAssembly(); 1.4 启动配置 在应用启动之前,abp 框架提供了模块基本的配置和方法,大家参照下面这个例子就可 以了。 译者注: 在看这一节的内容之前,建议大家先下载 module-zero 这个例子代码,这个例子就是一个用户和角色 的模块,并且使用的实例。配置在每一个应用中都可能会有,比如你有一个网站,你要获取网站的一些自 定义基本参数,比如 logo 位置,网站名称,上传文件大小等等。模块化的配置方式和我们之前的做法肯定 是不同的,大家要注意。之前无非就是一个方法 getconfig
21、从对应的表取数据,然后使用。 1.4.1 配置 ABP 配置是通过在自己模块的 PreInitialize 方法中来实现的(对于 module 的 PreInitialize 方 法,在上一篇中已经向大家做了简单的说明)代码示例如下: public class SimpleTaskSystemModule : AbpModule ABP Framework 入门开发指南 ABP 框架中国小组(ABPFrameWorkGroup) 版权所有 | 版本:1.0 12 public override void PreInitialize() /在你的应用中添加语言包,这个是英语和作者的土耳其语。 C
22、onfiguration.Localization.Languages.Add(new LanguageInfo(“en“, “English“, “famfamfam-flag-england“, true); Configuration.Localization.Languages.Add(new LanguageInfo(“tr“, “Trke“, “famfamfam-flag-tr“); Configuration.Localization.Sources.Add( new XmlLocalizationSource( “SimpleTaskSystem“, HttpContext.
23、Current.Server.MapPath(“/Localization/SimpleTaskSystem“) ) ); /配置导航和菜单 Configuration.Navigation.Providers.Add(); public override void Initialize() IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly(); 和 orchard 类似,abp 框架一开始就被设计成模块化的,不同的模块可以通过 abp 框架 来进行配置。举个例子吧,不同的模块都可以添加导航,通过导航添加
24、菜单项到自己定义的 主菜单,具体的细节大家可以参照: 本地化: 导航: ABP Framework 入门开发指南 ABP 框架中国小组(ABPFrameWorkGroup) 版权所有 | 版本:1.0 13 1.4.2 配置模块 和.net 框架原生的启动配置相比较, abp 有哪些不一样呢?abp 框架的模块可以通过 IAbpModuleConfigurations 接口进行个性化的扩展,这样的话,模块配置更加简单、方便。 示例代码如下: using Abp.Web.Configuration; . public override void PreInitialize() Configura
25、tion.Modules.AbpWeb().SendAllExceptionsToClients = true; 在上面这个例子中,我们通过配置 AbpWeb 模块,发送异常到客户端。当然了,不是每 一个模块都需要这种配置,通常情况下我们需要,是当一个模块需要在多个不同的应用中重 复使用,我们才进行这样的配置。 1.4.3 为一个模块创建配置 如下代码,假如我们有一个命名为 MyModule 的模块,并且这各模块有一些自己的配置。 那么我们首先要创建一些类,这些类定义为属性(译者注:属性有自动的 get 和 set 访问器。 ),代表了不同的配置。 public class MyModuleC
26、onfig public bool SampleConfig1 get; set; public string SampleConfig2 get; set; 接下来,我们通过依赖注入,注册这个类。 IocManager.Register(); 译者注: 在 IocManager 中注册了一个类,换句话说,我们通过 IocManager 可以得到这个类 MyModuleConfig 的 实例。至于 IOC 的原理这里就不在详细说了,总之,就是可以得到一个类的实例。 ABP Framework 入门开发指南 ABP 框架中国小组(ABPFrameWorkGroup) 版权所有 | 版本:1.0
27、14 最后,我们通过创建一个扩展的方法 IModuleConfigurations 来得到配置的引用。如下代 码: 译者注: 模块配置是一个静态类,因为我们需要重复使用它。静态方法 Mymodule 返回的是一个配置接口,参数 是 ImoduleConfigurations 接口。 现在,在其他模块中也可以配置我们自定义的这个 MyModule 模块了。 Configuration.Modules.MyModule().SampleConfig1 = false; Configuration.Modules.MyModule().SampleConfig2 = “test“; 在某种意义上,M
28、yModule 需要这些配置,通过注射 MyModuleConfig 我们就可以使用 这些值。 public class MyService : ITransientDependency private readonly MyModuleConfig _configuration; public MyService(MyModuleConfig configuration) _configuration = configuration; public void DoIt() if (_configuration.SampleConfig2 = “test“) /. ABP Framework
29、入门开发指南 ABP 框架中国小组(ABPFrameWorkGroup) 版权所有 | 版本:1.0 15 这意味着,在 abp 框架的系统中,所有的模块都可以集中配置。 (1.1 、1.2 由阳铭翻译,1.3、1.4 由天道翻译) ABP Framework 入门开发指南 ABP 框架中国小组(ABPFrameWorkGroup) 版权所有 | 版本:1.0 16 2 ABP 公共结构 2.1 ABP 依赖注入 如果你已经知道依赖注入的概念,构造函数和属性注入模式,你可以跳过这一节。 维基百科说:“依赖注入是一种软件设计模式,指一个或多个依赖(或服务)被注入, 或通过引用传递,传入一个依赖对
30、象(或客户端)并成为客户状态的一部分。模式通过自 身的行为分离了客户依赖的创建,这允许程序设计是松耦合的,同时遵循依赖倒置和单一 职责原则。与服务定位器模式直接进行对比,它允许客户了解他们用来查找依赖的机制。 ”。 如果不使用依赖注入技术,很难进行依赖管理、模块化开发和应用程序模块化。 2.1.1 传统方式的问题 在一个应用程序中,类之间相互依赖。假设我们有一个应用程序服务,使用仓储 (repository )类插入实体到数据库。在这种情况下,应用程序服务类依赖于仓储 (repository )类。看下例子: public class PersonAppService private IPer
31、sonRepository _personRepository; public PersonAppService() _personRepository = new PersonRepository(); public void CreatePerson(string name, int age) var person = new Person Name = name, Age = age ; _personRepository.Insert(person); ABP Framework 入门开发指南 ABP 框架中国小组(ABPFrameWorkGroup) 版权所有 | 版本:1.0 17
32、 PersonAppService 使用 PersonRepository 插入 Person 到数据库。这段代码的问题: PersonAppService 通过 IPersonRepository 调用 CreatePerson 方法,所以这方法 依赖于 IPersonRepository,代替了 PersonRepository 具体类。但 PersonAppService(的构造函数)仍然依赖于 PersonRepository。组件应该依赖 于接口而不是实现。这就是所谓的依赖性倒置原则。 如果 PersonAppService 亲自创建 PersonPeository,这变得依赖到了一
33、个特定的 IPersonRepository 接口实现,且不能使用另一个实现进行工作。因此,从实现分 离接口变得无意义,硬依赖使得代码基于紧耦合和低重用。硬依赖(hard- dependency)使得代码紧密耦合和较低的可重用。 我们可能需要在未来改变创建 PersonRepository 的方式。即,我们可能想让它创 建为单例(单一共享实例而不是为每个使用创建一个对象)。或者我们可能想要创建 多个类实现 IPersonRepository 并根据条件创建对象。在这种情况下,我们需要修 改所有依赖于 IPersonRepository 的类。 有了这样的依赖,很难(或不可能)对 PersonA
34、ppService 进行单元测试。 为了克服这些问题,可以使用工厂模式。因此,创建的仓储类是抽象的。看下面的代 码: public class PersonAppService private IPersonRepository _personRepository; public PersonAppService() _personRepository = PersonRepositoryFactory.Create(); public void CreatePerson(string name, int age) var person = new Person Name = name, Ag
35、e = age ; ABP Framework 入门开发指南 ABP 框架中国小组(ABPFrameWorkGroup) 版权所有 | 版本:1.0 18 _personRepository.Insert(person); PersonRepositoryFactory 是一个静态类,创建并返回一个 IPersonRepository。这就 是所谓的服务定位器模式。以上依赖问题得到解决,因为 PersonAppService 不需要创建 一个 IPersonRepository 的实现的对象,这个对象取决于 PersonRepositoryFactory 的 Create 方法。但是,仍然存在
36、一些问题: 此时,PersonAppService 取决于 PersonRepositoryFactory。这是更容易接受,但 仍有一个硬依赖(hard-dependency )。 为每个库或每个依赖项乏味的写一个工厂类/方法。 测试性依然不好,由于很难使得 PersonAppService 使用 mock 实现 IPersonRepository。 2.1.2 解决方案 有一些最佳实践(模式) 用于类依赖。 (1)构造函数注入 (Constructor injection) 重写上面的例子,如下所示: public class PersonAppService private IPerson
37、Repository _personRepository; public PersonAppService(IPersonRepository personRepository) _personRepository = personRepository; public void CreatePerson(string name, int age) var person = new Person Name = name, Age = age ; _personRepository.Insert(person); ABP Framework 入门开发指南 ABP 框架中国小组(ABPFrameWo
38、rkGroup) 版权所有 | 版本:1.0 19 这被称为构造函数注入。现在,PersonAppService 不知道哪些类实现 IPersonRepository 以及如何创建它。谁需要使用 PersonAppService,首先创建一个 IPersonRepository PersonAppService 并将其传递给构造函数,如下所示: var repository = new PersonRepository(); var personService = new PersonAppService(repository); personService.CreatePerson(“Yun
39、us Emre“, 19); 构造函数注入是一个完美的方法,使一个类独立创建依赖对象。但是,上面的代码有 一些问题: 创建一个 PersonAppService 变得困难。想想如果它有 4 个依赖,我们必须创建这 四个依赖对象,并将它们传递到构造函数 PersonAppService。 从属类可能有其他依赖项(在这里,PersonRepository 可能有依赖关系)。所以,我 们必须创建 PersonAppService 的所有依赖项,所有依赖项的依赖关系等等. .如此, 依赖关系使得我们创建一个对象变得过于复杂了。 幸运的是,依赖注入框架自动化管理依赖关系。 (2)属性注入 (Proper
40、ty injection) 采用构造函数的注入模式是一个完美的提供类的依赖关系的方式。通过这种方式,只 有提供了依赖你才能创建类的实例。同时这也是一个强大的方式显式地声明,类需要什么 样的依赖才能正确的工作。 但是,在有些情况下,该类依赖于另一个类,但也可以没有它。这通常是适用于横切 关注点( 如日志记录) 。一个类可以没有工作日志,但它可以写日志如果你提供一个日志对 象。在这种情况下,你可以定义依赖为公共属性,而不是让他们放在构造函数。想想,如 果我们想在 PersonAppService 写日志。我们可以重写类如下: public class PersonAppService public
41、 ILogger Logger get; set; private IPersonRepository _personRepository; public PersonAppService(IPersonRepository personRepository) ABP Framework 入门开发指南 ABP 框架中国小组(ABPFrameWorkGroup) 版权所有 | 版本:1.0 20 _personRepository = personRepository; Logger = NullLogger.Instance; public void CreatePerson(string n
42、ame, int age) Logger.Debug(“Inserting a new person to database with name = “ + name); var person = new Person Name = name, Age = age ; _personRepository.Insert(person); NullLogger.Instance 是一个单例对象,实现了 ILogger 接口,但实际上什么都没做 (不写日志。它实现了 ILogger 实例,且方法体为空)。现在,PersonAppService 可以写日 志了,如果你为 PersonAppServic
43、e 实例设置了 Logger,如下面: Var personService = new PersonAppService(new PersonRepository(); personService.Logger = new Log4NetLogger(); personService.CreatePerson(“Yunus Emre“, 19); 假设 Log4NetLogger 实现 ILogger 实例,使得我们可以使用 Log4Net 库写日志。因此, PersonAppService 可以写日志。如果我们不设置 Logger,PersonAppService 就不写日志。 因此,我们可
44、以说 PersonAppService ILogger 实例是一个可选的依赖。 几乎所有的依赖注入框架都支持属性注入模式。 2.1.3 依赖注入框架 有许多依赖注入框架,都可以自动解决依赖关系。他们可以创建所有依赖项(递归地依 赖和依赖关系) 。所以你只需要依赖注入模式写类和类构造函数 container.Register( Component.For().ImplementedBy().LifestyleT ransient(), Component.For().ImplementedBy().LifestyleT ransient() ); var personService = cont
45、ainer.Resolve(); personService.CreatePerson(“Yunus Emre“, 19); 我们首先创建了 WindsorContainer。然后注册 PersonRepository 和 PersonAppService 及它们的接口。然后我们要求容器创建一个 IPersonAppService 实例。 它创建 PersonAppService 对象及其依赖项并返回。在这个简单的示例中,使用 DI 框架也 许不是那么简洁,但想象下,在实际的企业应用程序中你会有很多类和依赖关系。当然, 注册的依赖项只在程序启动的某个地方创建一次。 请注意,我们只是将对象声明为
46、临时对象(transient)。这意味着每当我们创建这些类型 的一个对象时,就会创建一个新的实例。有许多不同的生命周期(如 Singletion 单例模式)。 2.1.4 ABP 依赖注入的基础结构 在编写应用程序时遵循最佳实践和一些约定,ABP 几乎让依赖注入框架使用变得无形。 (1)注册(Registering) 在 ABP 中,有很多种不同的方法来注册你的类到依赖注入系统。大部分时间,常规方 法就足够了。 (2)常规注册 (Conventional registrations) 按照约定,ABP 自动注册所有 Repositories, Domain Services, Applicat
47、ion ABP Framework 入门开发指南 ABP 框架中国小组(ABPFrameWorkGroup) 版权所有 | 版本:1.0 22 Services, MVC 控制器和 Web API 控制器。例如,你可能有一个 IPersonAppService 接口和实现类 PersonAppService: public interface IPersonAppService : IApplicationService /. public class PersonAppService : IPersonAppService /. ABP 会自动注册它,因为它实现 IApplicationSe
48、rvice 接口(它只是一个空的接口)。它 会被注册为 transient (每次使用都创建实例)。当你注入(使用构造函数注入) IPersonAppService 接口成一个类, PersonAppService 对象会被自动创建并传递给构造函 数。 注意: 命名约定在这里非常重要。例如你可以将名字 PersonAppService 改为 MyPersonAppService 或另 一个包含“PersonAppService”后缀的名称,由于 IPersonAppService 包含这个后缀。但是你可以不遵 循 PeopleService 命名你的服务类。如果你这样做,它将不会为 IPersonAppService 自动注册(它需要 自注册(self-registration)到 DI 框架,而不是接口),所以,如果你想要你应该手动注册它。 ABP 按照约定注册程序集。所以,你应该告诉 ABP 按照约定注册你的程序集。这很 容易: IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly(); Assembly.GetExecutingAssembly(