ABP's Dependency Injection system is developed based on Microsoft's [dependency injection extension](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection) library (Microsoft.Extensions.DependencyInjection nuget package). So, it's documentation is valid in ABP too.
Since ABP is a modular framework, every module defines it's own services and registers via dependency injection in it's own seperate [module class](Module-Development-Basics.md). Example:
public override void ConfigureServices(ServiceConfigurationContext context)
{
//register dependencies here
//在此处注入依赖项
}
}
````
### Conventional Registration
### 依照约定的注册
ABP introduces conventional service registration. You need not do anything to register a service by convention. It's automatically done. If you want to disable it, you can set `SkipAutoServiceRegistration` to `true` by overriding the `PreConfigureServices` method.
@ -30,7 +30,7 @@ public class BlogModule : AbpModule
}
````
Once you skip auto registration, you should manually register your services. In that case, ``AddAssemblyOf`` extension method can help you to register all your services by convention. Example:
``ExposeServicesAttribute`` is used to control which services are provided by the related class. Example:
``ExposeServicesAttribute``用于控制相关类提供了什么服务.例:
````C#
[ExposeServices(typeof(ITaxCalculator))]
@ -122,18 +122,18 @@ public class TaxCalculator: ICalculator, ITaxCalculator, ICanCalculate, ITransie
}
````
``TaxCalculator`` class only exposes ``ITaxCalculator`` interface. That means you can only inject ``ITaxCalculator``, but can not inject ``TaxCalculator`` or ``ICalculator`` in your application.
* The class itself is exposed by default. That means you can inject it by ``TaxCalculator`` class.
* Default interfaces are exposed by default. Default interfaces are determined by naming convention. In this example, ``ICalculator`` and ``ITaxCalculator`` are default interfaces of ``TaxCalculator``, but ``ICanCalculate`` is not.
Combining attributes and interfaces is possible as long as it's meaningful.
只要有意义,就可以组合属性和接口.
````C#
[Dependency(ReplaceServices = true)]
@ -144,31 +144,31 @@ public class TaxCalculator : ITaxCalculator, ITransientDependency
}
````
#### Manually Registering
#### 手动注册
In some cases, you may need to register a service to the `IServiceCollection` manually, especially if you need to use custom factory methods or singleton instances. In that case, you can directly add services just as [Microsoft documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection) describes. Example:
There are three common ways of using a service that has already been registered.
使用已注册的服务有三种常用方法.
#### Contructor Injection
#### 构造方法注入
This is the most common way of injecting a service into a class. For example:
这是将服务注入类的最常用方法.例如:
````C#
public class TaxAppService : ApplicationService
@ -182,18 +182,18 @@ public class TaxAppService : ApplicationService
public void DoSomething()
{
//...use _taxCalculator...
//...使用 _taxCalculator...
}
}
````
``TaxAppService`` gets ``ITaxCalculator`` in it's constructor. The dependency injection system automatically provides the requested service at runtime.
Constructor injection is preffered way of injecting dependencies to a class. In that way, the class can not be constructed unless all constructor-injected dependencies are provided. Thus, the class explicitly declares it's required services.
Property injection is not supported by Microsoft Dependency Injection library. However, ABP can integrate with 3rd-party DI providers ([Autofac](https://autofac.org/), for example) to make property injection possible. Example:
@ -207,24 +207,24 @@ public class MyService : ITransientDependency
public void DoSomething()
{
//...use Logger to write logs...
//...使用 Logger 写日志...
}
}
````
For a property-injection dependency, you declare a public property with public setter. This allows the DI framework to set it after creating your class.
对于属性注入依赖项,使用公开的setter声明公共属性.这允许DI框架在创建类之后设置它.
Property injected dependencies are generally considered as **optional** dependencies. That means the service can properly work without them. ``Logger`` is such a dependency, ``MyService`` can continue to work without logging.
To make the dependency properly optional, we generally set a default/fallback value to the dependency. In this sample, NullLogger is used as fallback. Thus, ``MyService`` can work but does not write logs if DI framework or you don't set Logger property after creating ``MyService``.
One restriction of property injection is that you cannot use the dependency in your constructor, since it's set after the object construction.
属性注入的一个限制是你不能在构造函数中使用依赖项,因为它是在对象构造之后设置的.
Property injection is also useful when you want to design a base class that has some common services injected by default. If you're going to use constructor injection, all derived classes should also inject depended services into their own constructors which makes development harder. However, be very careful using property injection for non-optional services as it makes it harder to clearly see the requirements of a class.
You may want to resolve a service directly from ``IServiceProvider``. In that case, you can inject IServiceProvider into your class and use ``GetService`` method as shown below:
@ -244,17 +244,17 @@ public class MyService : ITransientDependency
}
````
#### Releasing/Disposing Services
#### 释放/处理(Releasing/Disposing)服务
If you used a constructor or property injection, you don't need to be concerned about releasing the service's resources. However, if you have resolved a service from ``IServiceProvider``, you might, in some cases, need to take care about releasing the service resources.
ASP.NET Core releases all services at the end of a current HTTP request, even if you directly resolved from ``IServiceProvider`` (assuming you injected IServiceProvider). But, there are several cases where you may want to release/dispose manually resolved services:
ASP.NET Core会在当前HTTP请求结束时释放所有服务,即使你直接从``IServiceProvider``解析了服务(假设你注入了IServiceProvider).但是,在某些情况下,你可能希望释放/处理手动解析的服务:
* Your code is executed outside of AspNet Core request and the executer hasn't handled the service scope.
* You only have a reference to the root service provider.
* You may want to immediately release & dispose services (for example, you may creating too many services with big memory usage and don't want to overuse memory).