Asp.net core 学习笔记 ( DI 依赖注入 )
更新: 2021-06-29
什么时候用 singleton, scope, transient
更新: 2021-06-22
如果我们多次 AddScope
services.AddScoped<Person, Ali>();
services.AddScoped<Person, Mudu>();
注入的时候可以拿到 list 哦, 顺序就是看哪一个后注册咯
Person mudu,
IEnumerable<Person> muduAndAli
identity 的 UserValidator 就用了这个方式
更新 2020-01-11
动态创建 class 并且可以使用 DI, 这样反射样就可以了
var instance = ActivatorUtilities.CreateInstance<AbcService>(serviceProvider);
更新 2019-05-06
用泛型来传 class, 这样比较方便扩展
services.AddEmail<EmailService>();
services.AddEmail<NewEmailService>();
AddEmail
public static class ServiceCollectionExtensions { public static IServiceCollection AddEmail<TEmailService>( this IServiceCollection services ) where TEmailService : IEmailService { services.AddScoped(typeof(IEmailService), typeof(TEmailService)); return services; } } public interface IEmailService { string GetValue(); } public class EmailService : IEmailService { public string GetValue() { return "email v1"; } } public class NewEmailService : IEmailService { public string GetValue() { return "email v2"; } }
比起 Angular 的依赖注入, core 的相对简单许多, 容易明白
所有 provider 都在 startup 里配置.
public void ConfigureServices(IServiceCollection services) { services.Configure<Business>(Configuration.GetSection("business")); services.Configure<Configuration.Email>(Configuration.GetSection("email")); services.AddEmail(); // Razor template services.AddSingleton<ICompositeViewEngine, CompositeViewEngine>(); services.AddSingleton<IActionContextAccessor, ActionContextAccessor>(); // Entity services.AddScoped(_ => new DB(Configuration.GetConnectionString("DefaultConnection"))); // hangfire services.AddHangfire(config => config.UseSqlServerStorage(Configuration.GetConnectionString("DefaultConnection"))); // MVC services.Configure<RazorViewEngineOptions>(options => { options.ViewLocationExpanders.Add(new FeatureLocationExpander()); }); services.AddMvc(); }
controller 就通过 constructor 来注入就可以了.
private readonly DB db; private ICompositeViewEngine CompositeViewEngine { get; set; } private ActionContext ActionContext { get; set; } private IServiceProvider ServiceProvider { get; set; } private ITempDataProvider TempDataProvider { get; set; } private Configuration.Email EmailConfig { get; set; } public DebugController( DB db, ICompositeViewEngine compositeViewEngine, IActionContextAccessor actionContextAccessor, IServiceProvider serviceProvider, ITempDataProvider tempDataProvider, IOptionsSnapshot<Configuration.Email> emailOptionsAccessor ) { CompositeViewEngine = compositeViewEngine; ActionContext = actionContextAccessor.ActionContext; ServiceProvider = serviceProvider; TempDataProvider = tempDataProvider; EmailConfig = emailOptionsAccessor.Value; this.db = db; }
provider 有 3 个级别
AddSingleton
AddScoped
AddTransient
单列是说整个 App 用一个实例
Scope 一个 request 一个实例
transient 则是每一个注入一个实例
一个模块一般上会提供好多 Service
那么要让 startup 干净一些的话,我们可以包装起来
就好像这样 services.AddEmail();
做法是开一个扩展方法
namespace Project.Email { public static class ServiceCollectionExtensions { public static IServiceCollection AddEmail( this IServiceCollection services) { services.AddSingleton<ICompositeViewEngine, CompositeViewEngine>(); services.AddSingleton<IActionContextAccessor, ActionContextAccessor>(); services.AddScoped<EmailService, EmailService>(); return services; } } public class EmailService { public EmailService() { } public string name { get; set; } = "dada"; } }