相关文章:javascript
深刻理解net core中的依赖注入、Singleton、Scoped、Transient(一)php
深刻理解net core中的依赖注入、Singleton、Scoped、Transient(二)css
var controller = new AccountController(new EFLoginService()); controller.Login(userName, password); // 用Redis来替换原来的EF登陆 var controller = new AccountController(new RedisLoginService()); controller.Login(userName, password);
var serviceCollection = new ServiceCollection() .AddTransient<ILoginService, EFLoginService>() .AddSingleton<ILoginService, EFLoginService>() .AddScoped<ILoginService, EFLoginService>();
public interface IServiceCollection : IList<ServiceDescriptor> { }
咱们上面的AddTransient、AddSignletone和Scoped方法是IServiceCollection的扩展方法, 都是往这个List里面添加ServiceDescriptor。函数
private static IServiceCollection Add( IServiceCollection collection, Type serviceType, Type implementationType, ServiceLifetime lifetime) { var descriptor = new ServiceDescriptor(serviceType, implementationType, lifetime); collection.Add(descriptor); return collection; }
public enum ServiceLifetime { Singleton, Scoped, Transient }
public interface IOperation { Guid OperationId { get; } } public interface IOperationSingleton : IOperation { } public interface IOperationTransient : IOperation{} public interface IOperationScoped : IOperation{}
咱们的 Operation实现很简单,能够在构造函数中传入一个Guid进行赋值,若是没有的话则自已New一个 Guid。测试
public class Operation : IOperationSingleton, IOperationTransient, IOperationScoped { private Guid _guid; public Operation() { _guid = Guid.NewGuid(); } public Operation(Guid guid) { _guid = guid; } public Guid OperationId => _guid; }
在程序内咱们能够屡次调用ServiceProvider的GetService方法,获取到的都是同一个实例。ui
var services = new ServiceCollection(); // 默认构造 services.AddSingleton<IOperationSingleton, Operation>(); // 自定义传入Guid空值 services.AddSingleton<IOperationSingleton>( new Operation(Guid.Empty)); // 自定义传入一个New的Guid services.AddSingleton <IOperationSingleton>( new Operation(Guid.NewGuid())); var provider = services.BuildServiceProvider(); // 输出singletone1的Guid var singletone1 = provider.GetService<IOperationSingleton>(); Console.WriteLine($"signletone1: {singletone1.OperationId}"); // 输出singletone2的Guid var singletone2 = provider.GetService<IOperationSingleton>(); Console.WriteLine($"signletone2: {singletone2.OperationId}"); Console.WriteLine($"singletone1 == singletone2 ? : { singletone1 == singletone2 }");
咱们对IOperationSingleton注册了三次,最后获取两次,你们要注意到咱们获取到的始终都是咱们最后一次注册的那个给了一个Guid的实例,前面的会被覆盖。
此次咱们获取到的IOperationTransient为两个不一样的实例。
var services = new ServiceCollection(); services.AddTransient<IOperationTransient, Operation>(); var provider = services.BuildServiceProvider(); var transient1 = provider.GetService<IOperationTransient>(); Console.WriteLine($"transient1: {transient1.OperationId}"); var transient2 = provider.GetService<IOperationTransient>(); Console.WriteLine($"transient2: {transient2.OperationId}"); Console.WriteLine($"transient1 == transient2 ? : { transient1 == transient2 }");
var services = new ServiceCollection() .AddScoped<IOperationScoped, Operation>() .AddTransient<IOperationTransient, Operation>() .AddSingleton<IOperationSingleton, Operation>();
接下来咱们用ServiceProvider.CreateScope方法建立一个Scope
var provider = services.BuildServiceProvider(); using (var scope1 = provider.CreateScope()) { var p = scope1.ServiceProvider; var scopeobj1 = p.GetService<IOperationScoped>(); var transient1 = p.GetService<IOperationTransient>(); var singleton1 = p.GetService<IOperationSingleton>(); var scopeobj2 = p.GetService<IOperationScoped>(); var transient2 = p.GetService<IOperationTransient>(); var singleton2 = p.GetService<IOperationSingleton>(); Console.WriteLine( $"scope1: { scopeobj1.OperationId }," + $"transient1: {transient1.OperationId}, " + $"singleton1: {singleton1.OperationId}"); Console.WriteLine($"scope2: { scopeobj2.OperationId }, " + $"transient2: {transient2.OperationId}, " + $"singleton2: {singleton2.OperationId}"); }
接下来
scope1: 200d1e63-d024-4cd3-88c9-35fdf5c00956, transient1: fb35f570-713e-43fc-854c-972eed2fae52, singleton1: da6cf60f-670a-4a86-8fd6-01b635f74225 scope2: 200d1e63-d024-4cd3-88c9-35fdf5c00956, transient2: 2766a1ee-766f-4116-8a48-3e569de54259, singleton2: da6cf60f-670a-4a86-8fd6-01b635f74225
若是再建立一个新的Scope运行,
scope1: 29f127a7-baf5-4ab0-b264-fcced11d0729, transient1: 035d8bfc-c516-44a7-94a5-3720bd39ce57, singleton1: da6cf60f-670a-4a86-8fd6-01b635f74225 scope2: 29f127a7-baf5-4ab0-b264-fcced11d0729, transient2: 74c37151-6497-4223-b558-a4ffc1897d57, singleton2: da6cf60f-670a-4a86-8fd6-01b635f74225
public void ConfigureServices(IServiceCollection services) { services.AddTransient<ILoginService<ApplicationUser>, EFLoginService>(); services.AddMvc(); )
ASP.NET Core的一些组件已经提供了一些实例的绑定,像AddMvc就是Mvc Middleware在 IServiceCollection上添加的扩展方法。
public static IMvcBuilder AddMvc(this IServiceCollection services) { if (services == null) { throw new ArgumentNullException(nameof(services)); } var builder = services.AddMvcCore(); builder.AddApiExplorer(); builder.AddAuthorization(); AddDefaultFrameworkParts(builder.PartManager); ... }
private ILoginService<ApplicationUser> _loginService; public AccountController( ILoginService<ApplicationUser> loginService) { _loginService = loginService; }
咱们只要在控制器的构造函数里面写了这个参数,ServiceProvider就会帮咱们注入进来。这一步是在Mvc初始化控制器的时候完成的,咱们后面再介绍到Mvc的时候会往细里讲。
@using MilkStone.Services; @model MilkStone.Models.AccountViewModel.LoginViewModel @inject ILoginService<ApplicationUser> loginService <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head></head> <body> @loginService.GetUserName() </body> </html>
HttpContext.RequestServices.GetService<ILoginService<ApplicationUser>>();
builder.RegisterGeneric(typeof(LoggingBehavior<,>)).As(typeof(IPipelineBehavior<,>)); builder.RegisterGeneric(typeof(ValidatorBehavior<,>)).As(typeof(IPipelineBehavior<,>));
这会给咱们的初始化带来一些便利性,咱们来看看如何替换Autofac到ASP.NET Core。咱们只须要把Startup类里面的 ConfigureService的 返回值从 void改成 IServiceProvider便可。而返回的则是一个AutoServiceProvider。
public IServiceProvider ConfigureServices( IServiceCollection services){ services.AddMvc(); // Add other framework services // Add Autofac var containerBuilder = new ContainerBuilder(); containerBuilder.RegisterModule<DefaultModule>(); containerBuilder.Populate(services); var container = containerBuilder.Build(); return new AutofacServiceProvider(container); }
其中很大的一个变化在于,Autofac 原来的一个生命周期InstancePerRequest,将再也不有效。正如咱们前面所说的,整个request的生命周期被ASP.NET Core管理了,因此Autofac的这个将再也不有效。咱们可使用 InstancePerLifetimeScope ,一样是有用的,对应了咱们ASP.NET Core DI 里面的Scoped。