我想在ASP.NET Core中实现依赖项注入(DI)。因此,将这段代码添加到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
瞬态对象总是不同的。为每个控制器和每个服务提供一个新实例。
范围对象在一个请求中是相同的,但在不同的请求中是不同的。
每个对象和每个请求的单例对象都相同。
为了进一步说明,来自ASP.NET文档的此示例显示了以下区别:
为了说明这些生存期和注册选项之间的区别,请考虑一个简单的界面,该界面将一个或多个任务表示为具有唯一标识符的操作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,则使用新的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
,因此使用此类型时将很清楚。我们还注册了一个OperationService
依赖于其他每种Operation
类型的,因此对于每种操作类型,该请求将清楚地表明此服务是与控制器使用相同的实例,还是获得新的实例。该服务所做的全部工作就是将其依赖项公开为属性,以便可以在视图中显示它们。
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;
}
}
}
为了演示对应用程序的各个单独请求之内和之间的对象生存期,该示例包括一个OperationsController
请求每种类型的请求IOperation
以及一个请求OperationService
。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();
}
}
}
现在,对此控制器操作提出了两个单独的请求:
观察哪个OperationId
值在请求内以及请求之间变化。
瞬态对象总是不同的。为每个控制器和每个服务提供一个新实例。
范围对象在一个请求中是相同的,但在不同的请求中是不同的
每个对象和每个请求的单例对象都相同(无论是否在中提供了实例ConfigureServices
)
我理解它们每个的功能,但是有人可以解释使用其中一个而不是另一个的影响。如果使用不正确或选择一个而不是另一个,可能会导致什么问题。
假设您正在创建具有单例作用域的与请求上下文相关的对象(例如当前用户),则它将在所有不需要的http请求中保持相同的实例。IOC都是关于创建实例的,因此我们需要指定所创建实例的范围。
是!,我已经在主题顶部提到了链接!示例代码是从MS文档复制/粘贴的
谢谢。是的,无论会话/用户如何,整个应用程序中的单例都是相同的。显然,如果您的应用程序使用微服务架构,并且每个服务在单独的进程中运行,则每个进程中的单例将是相同的
您能给我们一个addTransient使用示例吗?因为当它使用太多资源时,我没有找到任何实用程序来使用它