在本例中,ICharacterRepository和ApplicationDbContext都必须在ConfigureServices中注册。ApplicationDbContext是通过扩展方法AddEntityFramework来配置,它包括添加DbContext (AddDbContext)的一个扩展。仓储的注入在在ConfigureServices方法的结尾。
services.AddTransient<ISmsSender, AuthMessageSender>(); services.AddScoped<ICharacterRepository, CharacterRepository>(); // Show different lifetime options services.AddTransient<IOperationTransient, Operation>();EF contexts需要使用scoped生命周期来添加到服务容器。如果你使用了上面的helper方法,这是已经处理好的。使用EF的仓储服务应该使用同样的生命周期。
警告:主要不安全的来源是通过单例来解析Scoped生命周期服务服务。这样做的后果,很有可能在处理后续请求时使用的服务的状态是错误的。
服务生命周期和注册选项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 IOperationInstance : IOperation { } }我们通过一个类来实现这些接口,接受一个Guid作为构造器参数,或者使用new Guid来提供(如果没有提供的话)。
接下来在ConfigureServices中,根据类型的生命周期来添加到容器中
注意到对于Instance生命周期的实例,我们是自己提供了已知的Guid.Empty标识符,这样我们能在该实例被使用时识别它。我们也注册了一个OperationService,它依赖其他Operation类型。这样我们就能弄清楚在一个请求内,对于每个类型我们是得到同样的实例还是一个新的实例。
using DependencyInjectionSample.Interfaces; namespace DependencyInjectionSample.Services { public class OperationService { public IOperationTransient TransientOperation { get; private set; } public IOperationScoped ScopedOperation { get; private set; } public IOperationSingleton SingletonOperation { get; private set; } public IOperationInstance InstanceOperation { get; private set; } public OperationService(IOperationTransient transientOperation, IOperationScoped scopedOperation, IOperationSingleton singletonOperation, IOperationInstance instanceOperation) { TransientOperation = transientOperation; ScopedOperation = scopedOperation; SingletonOperation = singletonOperation; InstanceOperation = instanceOperation; } } }为了演示对应用的单个请求内和不同请求内的对象生命周期,样例包含一个OperationController依赖每种类型的Operation以及OperationService。Index方法显示所有的服务Id。
using DependencyInjectionSample.Interfaces; using DependencyInjectionSample.Services; using Microsoft.AspNet.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 IOperationInstance _instanceOperation; public OperationsController(OperationService operationService, IOperationTransient transientOperation, IOperationScoped scopedOperation, IOperationSingleton singletonOperation, IOperationInstance instanceOperation) { _operationService = operationService; _transientOperation = transientOperation; _scopedOperation = scopedOperation; _singletonOperation = singletonOperation; _instanceOperation = instanceOperation; } public IActionResult Index() { ViewBag.Transient = _transientOperation; ViewBag.Scoped = _scopedOperation; ViewBag.Singleton = _singletonOperation; ViewBag.Instance = _instanceOperation; ViewBag.Service = _operationService; return View(); } } }