AddTransient, AddScoped and AddSingleton Services Differences?
我想在
1 2 3 4 5 6 7 8 | public void ConfigureServices(IServiceCollection services) { // Add framework services. // Add application services. services.AddTransient<IEmailSender, AuthMessageSender>(); services.AddScoped<IEmailSender, AuthMessageSender>(); } |
TL; DR
Transient objects are always different; a new instance is provided to
every controller and every service.Scoped objects are the same within a request, but different across
different requests.Singleton objects are the same for every object and every request.
为了进一步说明,来自asp.net docs的此示例显示了不同之处:
为了说明这些生存期和注册选项之间的区别,请考虑一个简单的界面,该界面将一个或多个任务表示为具有唯一标识符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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 { } } |
我们使用单个类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | using System; using DependencyInjectionSample.Interfaces; namespace DependencyInjectionSample.Classes { public class Operation : IOperationTransient, IOperationScoped, IOperationSingleton, IOperationSingletonInstance { Guid _guid; public Operation() : this(new Guid()) { } public Operation(Guid guid) { _guid = guid; } public Guid OperationId => _guid; } } |
接下来,在
1 2 3 4 5 | services.AddTransient<IOperationTransient, Operation>(); services.AddScoped<IOperationScoped, Operation>(); services.AddSingleton<IOperationSingleton, Operation>(); services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty)); services.AddTransient<OperationService, OperationService>(); |
请注意,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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; } } } |
为了演示对应用程序的各个单独请求之内和之间的对象生存期,该示例包括一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 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(); } } } |
现在,对此控制器操作提出了两个单独的请求:
观察哪个
-
瞬态对象总是不同的。为每个控制器和每个服务提供一个新实例。
-
范围对象在一个请求中是相同的,但在不同的请求中是不同的
-
每个对象和每个请求的单例对象都是相同的(无论是否在
ConfigureServices 中提供了实例)
在dotnet的依赖注入中,有3个主要生命周期:
Singleton,它将在整个应用程序中创建一个实例。它第一次创建实例,并在所有调用中重用相同的对象。
范围内的生命周期服务在范围内为每个请求创建一次。在当前范围内等效于Singleton。例如。在MVC中,每个HTTP请求创建1个实例,但在同一Web请求中的其他调用中使用相同的实例。
每次请求时都会创建瞬态生存期服务。此生命周期最适合轻量级无状态服务。
在这里您可以找到示例,以查看两者之间的区别:
http://dotnetliberty.com/index.php/2015/10/15/asp-net-5-mvc6-dependency-injection-in-6-steps/
Your Dependency Injection ready ASP.NET : ASP.NET 5
这是官方文档的链接:
https://docs.asp.net/en/latest/fundamentals/dependency-injection.html#service-lifetimes-and-registration-options
-
Singleton是应用程序生命周期中的单个实例
域。 -
范围是范围内持续时间的单个实例
请求,即ASP.NET中的每个HTTP请求。 - 瞬态是每个代码请求的单个实例。
通常,代码请求应通过构造函数参数进行,如
1 | public MyConsumingClass(IDependency dependency) |
我想在@akazemis的回答中指出,DI上下文中的"服务"并不意味着RESTful服务;服务是提供功能的依赖项的实现。
当必须注入多个相同类型的对象时,可以在ASP.NET MVC核心DI中使用瞬态,作用域和单例定义对象创建过程。如果您是依赖注入的新手,可以观看此DI IOC视频
您可以看到以下控制器代码,其中我已在构造函数中请求了两个" IDal"实例。 Transient,Scoped和Singleton定义将以" _dal"和" _dal1"注入相同实例还是以不同实例注入。
1 2 3 4 5 6 7 8 9 10 11 | public class CustomerController : Controller { IDal dal = null; public CustomerController(IDal _dal ,IDal _dal1) { dal = _dal; // DI of MVC core // inversion of control } } |
瞬态:-在瞬态中,新对象实例将被注入单个Request和Response中。下面是我显示GUID值的快照图像。
范围:-在范围内,同一对象实例将注入单个请求和响应中。
Singleton:在Singleton中,将在所有请求和响应中注入相同的对象。在这种情况下,将创建该对象的一个??全局实例。
下面是一个简单的图表,从视觉上解释了上面的基本原理。
上面的图像是我在孟买接受ASP.NET MVC培训时由SBSS团队绘制的,这非常感谢SBSS团队创建了上面的图像。
AddSingleton()
当首次请求该服务时,AddSingleton()将创建该服务的单个实例,并在需要该服务的所有位置重用该实例。
AddScoped()
在具有每个http请求的范围服务中,我们获得了一个新实例。但是,对于同一个http请求,如果在多个位置(如视图和控制器中)都需要该服务,则将为该http请求的整个范围提供相同的实例。但是,每个新的http请求都将获得该服务的新实例。
AddTransient()
对于临时服务,每次请求服务实例时,无论是在同一http请求的范围内还是跨不同的http请求,都会提供一个新实例。
在寻找该问题的答案之后,我找到了一个精妙的解释,并举了一个例子,我想与您分享。
您可以在此处观看展示差异的视频
在此示例中,我们具有以下给定代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | public interface IEmployeeRepository { IEnumerable<Employee> GetAllEmployees(); Employee Add(Employee employee); } public class Employee { public int Id { get; set; } public string Name { get; set; } } public class MockEmployeeRepository : IEmployeeRepository { private List<Employee> _employeeList; public MockEmployeeRepository() { _employeeList = new List<Employee>() { new Employee() { Id = 1, Name ="Mary" }, new Employee() { Id = 2, Name ="John" }, new Employee() { Id = 3, Name ="Sam" }, }; } public Employee Add(Employee employee) { employee.Id = _employeeList.Max(e => e.Id) + 1; _employeeList.Add(employee); return employee; } public IEnumerable<Employee> GetAllEmployees() { return _employeeList; } } |
HomeController的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | public class HomeController : Controller { private IEmployeeRepository _employeeRepository; public HomeController(IEmployeeRepository employeeRepository) { _employeeRepository = employeeRepository; } [HttpGet] public ViewResult Create() { return View(); } [HttpPost] public IActionResult Create(Employee employee) { if (ModelState.IsValid) { Employee newEmployee = _employeeRepository.Add(employee); } return View(); } } |
建立检视
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | @model Employee @inject IEmployeeRepository empRepository <form asp-controller="home" asp-action="create" method="post"> <label asp-for="Name"></label> <input asp-for="Name"> <button type="submit">Create</button> Total Employees Count = @empRepository.GetAllEmployees().Count().ToString() </form> |
Startup.cs
1 2 3 4 5 | public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddSingleton<IEmployeeRepository, MockEmployeeRepository>(); } |
复制并粘贴此代码,然后在视图中按创建按钮,然后在
AddSingleton() - As the name implies, AddSingleton() method creates a
Singleton service. A Singleton service is created when it is first
requested. This same instance is then used by all the subsequent
requests. So in general, a Singleton service is created only one time
per application and that single instance is used throughout the
application life time.AddTransient() - This method creates a Transient service. A new
instance of a Transient service is created each time it is requested.AddScoped() - This method creates a Scoped service. A new instance of
a Scoped service is created once per request within the scope. For
example, in a web application it creates 1 instance per each http
request but uses the same instance in the other calls within that same
web request.
如此处所述(此链接非常有用)和示例,
This mapping between the interface and the concrete type defines, that everytime you request a type of IContryService, you'll get a new instance of the CountryService. This is what transient means in this case. You are also able to add singleton mappings (using AddSingleton) and scoped mappings (using AddScoped). Scoped in this case means scoped to a HTTP request, which also means it is a singleton while the current request is running. You can also add an existing instance to the DI container using the method AddInstance.
These are the almost complete ways to register to the IServiceCollection