Asp.net core 学习笔记 ( DI 依赖注入 )

更新: 2021-06-29

什么时候用 singleton, scope, transient 

https://stackoverflow.com/questions/38138100/addtransient-addscoped-and-addsingleton-services-differences

更新: 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";
    }
}
原文地址:https://www.cnblogs.com/keatkeat/p/7742543.html