我想在Asp.Net Core
中实现依赖性注入
。所以在ConfigureServices
方法中加入这些代码后,两种方式都能工作。
在Asp.Net Core
中,services.AddTransient
和service.AddScoped
方法有什么区别?
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddScoped<IEmailSender, AuthMessageSender>();
}
TL;DR
瞬时对象总是不同的;一个新的实例被提供给 每个控制器和每个服务。
范围对象在一个请求中是相同的,但在不同的请求中是不同的。 不同的请求之间是不同的。
Singleton对象对每个对象和每个请求都是一样的。
为了更清楚地说明,这个来自asp.net docs的例子显示了其中的区别。
为了证明这些寿命和注册选项之间的区别,考虑一个简单的接口,它将一个或多个任务表示为一个具有唯一标识符OperationId
的操作。根据我们为这个服务配置寿命的方式,容器将为请求的类提供相同或不同的服务实例。为了清楚地说明正在请求哪种寿命,我们将为每个寿命选项创建一个类型。
using System;
namespace DependencyInjectionSample.Interfaces
{
public interface IOperation
{
Guid OperationId { get; }
}
public interface IOperationTransient : IOperation
{
}
public interface IOperationScoped : IOperation
{
}
public interface IOperationSingleton : IOperation
{
}
public interface IOperationSingletonInstance : IOperation
{
}
}
我们使用一个单一的类Operation
来实现这些接口,该类在构造函数中接受一个Guid
,如果没有提供,则使用一个新的Guid
。
using System;
using DependencyInjectionSample.Interfaces;
namespace DependencyInjectionSample.Classes
{
public class Operation : IOperationTransient, IOperationScoped, IOperationSingleton, IOperationSingletonInstance
{
Guid _guid;
public Operation() : this(Guid.NewGuid())
{
}
public Operation(Guid guid)
{
_guid = guid;
}
public Guid OperationId => _guid;
}
}
接下来,在ConfigureServices
中,每个类型都根据其命名的寿命被添加到容器中。
services.AddTransient<IOperationTransient, Operation>();
services.AddScoped<IOperationScoped, Operation>();
services.AddSingleton<IOperationSingleton, Operation>();
services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty));
services.AddTransient<OperationService, OperationService>();
注意,IOperationSingletonInstance
服务正在使用一个已知ID为Guid.Empty
的特定实例,所以当这个类型被使用时,会很清楚。我们还注册了一个依赖其他每个 "操作 "类型的 "操作服务",这样在请求中就可以清楚地知道这个服务是获得与控制器相同的实例,还是一个新的操作类型。这个服务所做的就是把它的依赖关系作为属性公开,所以它们可以在视图中显示。
using DependencyInjectionSample.Interfaces;
namespace DependencyInjectionSample.Services
{
public class OperationService
{
public IOperationTransient TransientOperation { get; }
public IOperationScoped ScopedOperation { get; }
public IOperationSingleton SingletonOperation { get; }
public IOperationSingletonInstance SingletonInstanceOperation { get; }
public OperationService(IOperationTransient transientOperation,
IOperationScoped scopedOperation,
IOperationSingleton singletonOperation,
IOperationSingletonInstance instanceOperation)
{
TransientOperation = transientOperation;
ScopedOperation = scopedOperation;
SingletonOperation = singletonOperation;
SingletonInstanceOperation = instanceOperation;
}
}
}
为了展示应用程序内部和单独请求之间的对象寿命,该样本包括一个 "操作控制器",该控制器请求每种 "操作 "类型以及 "操作服务"。然后 "Index "动作显示所有控制器和服务的 "OperationId "值。
using DependencyInjectionSample.Interfaces;
using DependencyInjectionSample.Services;
using Microsoft.AspNetCore.Mvc;
namespace DependencyInjectionSample.Controllers
{
public class OperationsController : Controller
{
private readonly OperationService _operationService;
private readonly IOperationTransient _transientOperation;
private readonly IOperationScoped _scopedOperation;
private readonly IOperationSingleton _singletonOperation;
private readonly IOperationSingletonInstance _singletonInstanceOperation;
public OperationsController(OperationService operationService,
IOperationTransient transientOperation,
IOperationScoped scopedOperation,
IOperationSingleton singletonOperation,
IOperationSingletonInstance singletonInstanceOperation)
{
_operationService = operationService;
_transientOperation = transientOperation;
_scopedOperation = scopedOperation;
_singletonOperation = singletonOperation;
_singletonInstanceOperation = singletonInstanceOperation;
}
public IActionResult Index()
{
// viewbag contains controller-requested services
ViewBag.Transient = _transientOperation;
ViewBag.Scoped = _scopedOperation;
ViewBag.Singleton = _singletonOperation;
ViewBag.SingletonInstance = _singletonInstanceOperation;
// operation service has its own requested services
ViewBag.Service = _operationService;
return View();
}
}
}
现在向这个控制器动作发出了两个单独的请求。 ![第一个请求][2]
观察在一个请求中,以及在不同的请求之间,哪些 "OperationId "值会发生变化。
瞬时对象总是不同的;一个新的实例被提供给每个控制器和每个服务。
范围对象在一个请求中是相同的,但在不同的请求中是不同的。
单子对象对每个对象和每个请求都是一样的(不管实例是否在ConfigureServices
中提供)。
在dotnet'的依赖注入中,有3个主要的生命期。
Singleton它在整个应用程序中创建一个单一的实例。它首次创建实例并在所有调用中重复使用同一对象。
范围生命周期的服务是在范围内的每个请求创建一次。例如,在MVC中,它为每个http请求创建一个实例,但在同一web请求的其他调用中使用同一个实例。
Transient生命周期的服务在每次被请求时都会被创建。这种生命周期最适合于轻量级、无状态的服务。
在这里,你可以找到一些例子来看看其中的区别。
http://dotnetliberty.com/index.php/2015/10/15/asp-net-5-mvc6-dependency-injection-in-6-steps/
https://codewala.net/2015/04/30/your-dependency-injection-ready-asp-net-asp-net-5/
而这是官方文件的链接。
在ASP.NET MVC核心DI中,当多个相同类型的对象必须被注入时,暂存、范围和单子定义了对象的创建过程。如果你是依赖注入的新手,你可以看看这个[DI IOC视频][1] 。
你可以看到下面的控制器代码,我在构造函数中请求了两个"IDal" 的实例。Transient,Scoped和Singleton定义了同一个实例是否会被注入到"_dal"和"_dal1"中,还是不同的。
public class CustomerController : Controller
{
IDal dal = null;
public CustomerController(IDal _dal
,IDal _dal1)
{
dal = _dal;
// DI of MVC core
// inversion of control
}
}
Transient :- 在transient中,新的对象实例将被注入到单个请求和响应中。下面是一个我显示GUID值的快照图片。
Scoped :- 在Scoped中,相同的对象实例将被注入到单个请求和响应中。
Singleton :- 在Singleton中,同一个对象将被注入到所有的请求和响应中。在这种情况下,该对象的一个全局实例将被创建。
下面是一个简单的图表,它直观地解释了上述基本原理。
以上图片是我在参加孟买ASP.NET MVC培训培训时由SBSS团队绘制的,非常感谢SBSS团队绘制了以上图片。