Skip to content

Net Core 内置 DI 容器解读 #40

@Henrik-Xu

Description

@Henrik-Xu

.NetCore 内置容器

NetCore 服务生命周期

services.AddTransient<IServiceA, ObjectA>(); // 瞬时模式 每次获取都会创建一个新的实例
services.AddSingleton<IServiceB, ObjectB>(); // 单例模式:实例只在第一次获取的时候创建,以后每次获取都是这个实例
services.AddScoped<IServiceC, ObjectC>();    // 作用域模式:每次 web 请求都是新实例,同一个 web 请求都是相同的实例

Startup 源码分析

先说结论:StartUp 是通过反射调用的,这个对象创建的时候,容器都已经提前完成,方法调用的时候,

直接把容器传递过去,供开发使用。

  1. public IConfiguration Configuration { get; }

Configuration 属性是配置系统要用到的对象,通过构造方法注入。

public Startup(IConfiguration configuration)
{
    Configuration = configuration;
}
  1. public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

注册请求中间件,这些中间件按照一定顺序添加,组成中间管道。

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

NetCore 容器框架使用

第一步:服务注册

第二步:构造方法注入

  1. 实体类
//定义一组接口
public interface IServiceA
{
    void Operation();
}

public interface IServiceB
{
    void Operation();
}

public interface IServiceC
{
    void Operation();
}

public interface IServiceD
{
    void Operation();
}
  1. 业务类
/// <summary>
/// 服务A的实现
/// </summary>
public class ObjectA : IServiceA
{
    public ObjectA()
    {
        Console.WriteLine("ObjectA  is Created!");
    }
    public void Operation()=> Console.WriteLine("ObjectA.Operation()  is Called!");        
}

/// <summary>
/// 服务B的实现
/// </summary>
public class ObjectB : IServiceB
{
    private readonly IServiceA serviceA;
    public ObjectB(IServiceA service)
    {
        this.serviceA = service;
        Console.WriteLine("ObjectB  is Created!");           
    }
    public void Operation()
    {
        Console.WriteLine("--------------------------------------------");
        this.serviceA.Operation();
        Console.WriteLine("ObjectB.Operation()  is Called!");
    }      
}

  /// <summary>
/// 服务C的实现
/// </summary>
public class ObjectC : IServiceC
{       
    private readonly IServiceB serviceB;
    public ObjectC(IServiceB service)
    {
        this.serviceB = service;
        Console.WriteLine("ObjectC  is Created!");          
    }
    public void Operation() => Console.WriteLine("ObjectC.Operation()  is Called!");       
}

/// <summary>
/// 服务D的实现
/// </summary>
public class ObjectD : IServiceD
{
    private readonly IServiceA _serviceA; 
    private readonly IServiceB _serviceB;
    private readonly IServiceC _serviceC;
    public ObjectD(IServiceA serviceA, IServiceB serviceB, IServiceC serviceC)
    {
        this._serviceA = serviceA;
        this._serviceB = serviceB;
        this._serviceC = serviceC;
        Console.WriteLine("ObjectD  is Created!");            
    }
    public void Operation()
    {
        Console.WriteLine("---------------------------------------");
        this._serviceA.Operation();
        this._serviceB.Operation();
        this._serviceC.Operation();
        Console.WriteLine("ObjectD.Operation()  is Called!");
    }
}
  1. 注册服务
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();

    //注入我们自己需要的服务
    services.AddTransient<IServiceA, ObjectA>(); 
    services.AddSingleton<IServiceB, ObjectB>();  
    services.AddScoped<IServiceC, ObjectC>();    
    services.AddTransient<IServiceD, ObjectD>();
}
  1. 配置 log4Net

Log4Net.config

<?xml version="1.0" encoding="utf-8"?>
<log4net>
<!-- Define some output appenders -->
<appender name="rollingAppender" type="log4net.Appender.RollingFileAppender">
  <file value="MyProjectLog\log.txt" />
  <!--追加日志内容-->
  <appendToFile value="true" />

  <!--防止多线程时不能写Log,官方说线程非安全-->
  <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />

  <!--可以为:Once|Size|Date|Composite-->
  <!--Composite为Size和Date的组合-->
  <rollingStyle value="Composite" />

  <!--当备份文件时,为文件名加的后缀-->
  <datePattern value="yyyyMMdd.TXT" />

  <!--日志最大个数,都是最新的-->
  <!--rollingStyle节点为Size时,只能有value个日志-->
  <!--rollingStyle节点为Composite时,每天有value个日志-->
  <maxSizeRollBackups value="20" />

  <!--可用的单位:KB|MB|GB-->
  <maximumFileSize value="3MB" />

  <!--置为true,当前最新日志文件名永远为file节中的名字-->
  <staticLogFileName value="true" />

  <!--输出级别在INFO和ERROR之间的日志-->
  <filter type="log4net.Filter.LevelRangeFilter">
    <param name="LevelMin" value="ALL" />
    <param name="LevelMax" value="FATAL" />
  </filter>
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/>
  </layout>
</appender>
<root>
  <priority value="ALL"/>
  <level value="ALL"/>
  <appender-ref ref="rollingAppender" />
</root>
</log4net>
  1. 添加 log4Net 日志
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env,
    ILoggerFactory loggerFactory)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    loggerFactory.AddLog4Net();  //添加log4Net日志

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}
  1. 服务使用

Controller 中使用服务

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;
    private readonly ILoggerFactory _loggerFactory;
    private readonly IServiceA _serviceA;
    private readonly IServiceB _serviceB;
    private readonly IServiceC _serviceC;
    public HomeController(ILogger<HomeController> logger,ILoggerFactory loggerFactory,
        IServiceA serviceA, IServiceB serviceB, IServiceC serviceC)
    {
        _logger = logger;
        _loggerFactory = loggerFactory;
        this._serviceA = serviceA;
        this._serviceB = serviceB;
        this._serviceC = serviceC; 
    }
  

    public IActionResult Index()
    {
        this._serviceA.Operation();
        this._serviceB.Operation();
        this._serviceC.Operation();

        //this._logger.LogInformation("这个是 this._logger.LogInformation的输出!");
        //this._logger.LogWarning("这个是 this._logger.LogWarning!");
        //this._logger.LogError("这个是 this._logger.LogError!");

        this._loggerFactory.CreateLogger<HomeController>().LogInformation("这个是 this._loggerFactory.LogInformation的输出!");
        this._loggerFactory.CreateLogger<HomeController>().LogWarning("这个是 this._loggerFactory.LogWarning!");
        this._loggerFactory.CreateLogger<HomeController>().LogError("这个是 this._loggerFactory.LogError!");

        return View();
    }
}

StartUp 类不是必须的

public static IHostBuilder CreateHostBuilder(string[] args) =>
          Host.CreateDefaultBuilder(args)
              .ConfigureWebHostDefaults(webBuilder =>
              {
                  // webBuilder.UseStartup<Startup>();
                  webBuilder.ConfigureServices(services =>
                  {
                      services.AddControllersWithViews();

                      //注入我们自己需要的服务
                      services.AddTransient<IServiceA, ObjectA>(); 
                      services.AddSingleton<IServiceB, ObjectB>();  
                      services.AddScoped<IServiceC, ObjectC>();    
                      services.AddTransient<IServiceD, ObjectD>();
                  });

                  webBuilder.Configure(app =>
                  {
                      app.UseRouting();

                      app.UseEndpoints(endpoints =>
                      {
                          endpoints.MapControllerRoute(
                              name: "default",
                              pattern: "{controller=Home}/{action=Index}/{id?}");
                      });
                  });

              });

总结: 系统自带框架一般都为构造方法注入,并没有那么强大。若需要更强大的依赖注入(AOP 等),需要引如第三方框架,

比如 Autofac...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions