ABP Framework入门开发指南
IPersonRepository PersonAppService并将其传递给构造函数,如下所示:
var repository = new PersonRepository();
var personService = new PersonAppService(repository); personService.CreatePerson(\, 19);
构造函数注入是一个完美的方法,使一个类独立创建依赖对象。但是,上面的代码有一些问题:
? 创建一个PersonAppService变得困难。想想如果它有4个依赖,我们必须创建这
四个依赖对象,并将它们传递到构造函数PersonAppService。
? 从属类可能有其他依赖项(在这里,PersonRepository可能有依赖关系)。所以,我
们必须创建PersonAppService的所有依赖项,所有依赖项的依赖关系等等. .如此,依赖关系使得我们创建一个对象变得过于复杂了。 幸运的是,依赖注入框架自动化管理依赖关系。 (2)属性注入(Property injection)
采用构造函数的注入模式是一个完美的提供类的依赖关系的方式。通过这种方式,只有提供了依赖你才能创建类的实例。同时这也是一个强大的方式显式地声明,类需要什么样的依赖才能正确的工作。
但是,在有些情况下,该类依赖于另一个类,但也可以没有它。这通常是适用于横切关注点(如日志记录)。一个类可以没有工作日志,但它可以写日志如果你提供一个日志对象。在这种情况下,你可以定义依赖为公共属性,而不是让他们放在构造函数。想想,如果我们想在PersonAppService写日志。我们可以重写类如下:
public class PersonAppService {
public ILogger Logger { get; set; }
private IPersonRepository _personRepository;
public PersonAppService(IPersonRepository personRepository) {
_personRepository = personRepository; Logger = NullLogger.Instance; }
ABP框架中国小组(ABPFrameWorkGroup)版权所有 | 版本:1.019
ABP Framework入门开发指南
public void CreatePerson(string name, int age) {
Logger.Debug(\ var person = new Person { Name = name, Age = age }; _personRepository.Insert(person);
NullLogger.Instance 是一个单例对象,实现了ILogger接口,但实际上什么都没做(不写日志。它实现了ILogger实例,且方法体为空)。现在,PersonAppService可以写日志了,如果你为PersonAppService实例设置了Logger,如下面:
VarpersonService = new PersonAppService(new PersonRepository()); personService.Logger = new Log4NetLogger(); personService.CreatePerson(\
假设Log4NetLogger实现ILogger实例,使得我们可以使用Log4Net库写日志。因此,PersonAppService可以写日志。如果我们不设置Logger,PersonAppService就不写日志。因此,我们可以说PersonAppService ILogger实例是一个可选的依赖。
几乎所有的依赖注入框架都支持属性注入模式。 2.1.3 依赖注入框架
有许多依赖注入框架,都可以自动解决依赖关系。他们可以创建所有依赖项(递归地依赖和依赖关系)。所以你只需要依赖注入模式写类和类构造函数&属性,其他的交给DI框架处理!在良好的应用程序中,类甚至独立于DI框架。整个应用程序只会有几行代码或类,显示的与DI框架交互。
ABP的依赖注入基于 Castle Windsor框架。Castle Windsor最成熟的DI框架之一。还有很多这样的框架,如Unity,Ninject,StructureMap,Autofac等等。
在使用一个依赖注入框架时,首先注册你的接口/类到依赖注入框架中,然后你就可以resolve一个对象。在Castle Windsor,它是这样的:
var container = new WindsorContainer();
container.Register(
Component.For
ABP框架中国小组(ABPFrameWorkGroup)版权所有 | 版本:1.020
ABP Framework入门开发指南
ransient(),
Component.For
var personService = container.Resolve
我们首先创建了WindsorContainer。然后注册PersonRepository 和
PersonAppService及它们的接口。然后我们要求容器创建一个IPersonAppService实例。它创建PersonAppService对象及其依赖项并返回。在这个简单的示例中,使用DI框架也许不是那么简洁,但想象下,在实际的企业应用程序中你会有很多类和依赖关系。当然,注册的依赖项只在程序启动的某个地方创建一次。
请注意,我们只是将对象声明为临时对象(transient)。这意味着每当我们创建这些类型的一个对象时,就会创建一个新的实例。有许多不同的生命周期(如Singletion单例模式)。 2.1.4 ABP依赖注入的基础结构
在编写应用程序时遵循最佳实践和一些约定,ABP几乎让依赖注入框架使用变得无形。 (1)注册(Registering)
在ABP中,有很多种不同的方法来注册你的类到依赖注入系统。大部分时间,常规方法就足够了。
(2)常规注册(Conventional registrations)
按照约定,ABP自动注册所有 Repositories, Domain Services, Application Services, MVC 控制器和Web API控制器。例如,你可能有一个IPersonAppService 接口和实现类PersonAppService:
public interface IPersonAppService : IApplicationService {
//... }
ABP框架中国小组(ABPFrameWorkGroup)版权所有 | 版本:1.021
ABP Framework入门开发指南
public class PersonAppService : IPersonAppService {
//... }
ABP会自动注册它,因为它实现IApplicationService接口(它只是一个空的接口)。它会被注册为transient (每次使用都创建实例)。当你注入(使用构造函数注入)IPersonAppService接口成一个类,PersonAppService对象会被自动创建并传递给构造函数。
注意:
命名约定在这里非常重要。例如你可以将名字PersonAppService改为 MyPersonAppService或另一个包含“PersonAppService”后缀的名称,由于IPersonAppService包含这个后缀。但是你可以不遵循PeopleService命名你的服务类。如果你这样做,它将不会为IPersonAppService自动注册(它需要自注册(self-registration)到DI框架,而不是接口),所以,如果你想要你应该手动注册它。
ABP按照约定注册程序集。所以,你应该告诉ABP按照约定注册你的程序集。这很容易:
IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());
Assembly.GetExecutingAssembly()得到一个对包括此代码的程序集的引用。你可以通过RegisterAssemblyByConvention方法注册其他程序集。这同在你的模块初始化(AbpModule.Initialize())时完成。请查看ABP的模块系统获得更多信息。
你可以通过实现
IConventionalRegisterer
接口和调用
IocManager。
AddConventionalRegisterer方法编写自己的约定注册类。你应该将它添加到模块的pre-initialize方法中。
(3)帮助接口(Helper interfaces)
你可以注册一个特定的类,不遵循传统的约定制度规则。ABP提供了ITransientDependency和ISingletonDependency接口的快捷方法。例如:
public interface IPersonManager {
//... }
ABP框架中国小组(ABPFrameWorkGroup)版权所有 | 版本:1.022
ABP Framework入门开发指南
public class MyPersonManager : IPersonManager, ISingletonDependency {
//... }
以这种方式,你可以很容易地注册MyPersonManager为transient。当需要注入IPersonManager时,MyPersonManager会被使用。注意,依赖被声明为单例。因此,创建的MyPersonManager同一个对象被传递给所有需要的类。只是在第一次使用时创建,那么应用程序的整生命周期使用的是同一实例。
(4)自定义/直接注册(Custom/Direct registration)
如果之前描述的方法还是不足以应对你的情况,你可以使用Castle Windsor注册类和及依赖项。因此,你将拥有Castle Windsor注册的所有能力。
可以实现IWindsorInstaller接口进行注册。你可以在应用程序中创建一个实现IWindsorInstaller接口的类:
public class MyInstaller : IWindsorInstaller {
public void Install(IWindsorContainer container, IConfigurationStore store) {
container.Register(Classes.FromThisAssembly().BasedOn
Abp自动发现和执行这个类。最后,你可以通过使用IIocManager.IocContainer属性得到WindsorContainer。有关更多信息,阅读Windsor的文档。
(5)解析(Resolving)
注册通知IOC(控制反转)容器关于你的类,它们的依赖项和生命周期。在你的应用程序需要使用IOC容器创建对象时,ASP.NET提供了一些方法解决依赖关系。
(6)构造函数&属性注入(Constructor & Property Injection)
作为最佳实践,你可以使用构造函数和属性注入去获取你的类的依赖。任何可能的地方,你都应该这样做。例子:
ABP框架中国小组(ABPFrameWorkGroup)版权所有 | 版本:1.023