当前位置:   article > 正文

.NET 依赖注入和配置系统

.NET 依赖注入和配置系统

依赖注入

依赖注入(Dependency Injection,DI)是控制反转(Inversion of Control,IOC)思想的实现方式。

控制反转的两种实现方式:

  1. 服务定位器(ServiceLocator);
  2. 依赖注入(Dependency Injection,DI);

DI几个概念

服务(service):对象;
注册服务
服务容器:负责管理注册的服务;
查询服务:创建对象及关联对象;
对象生命周期:Transient(瞬态); Scoped(范围); Singleton(单例);

.NET 中使用DI

1、Install-Package Microsoft.Extensions.DependencyInjection
2、using Microsoft.Extensions.DependencyInjection
3、ServiceCollection用来构造容器对象IServiceProvider 。调用ServiceCollectionBuildServiceProvider()创建的ServiceProvider,可以用来获取BuildServiceProvider()之前ServiceCollection中的对象。

  internal interface ITestService
  {
      public string Name { get; set; }
      public void SayHi();
  }

   internal class TestServiceImpl
 {
     public string Name { get; set; }
     public void SayHi()
     {
         Console.WriteLine($"Hi, I'm {Name}");
     }
 }

 internal class TestServiceImpl2
{
    public string Name { get; set; }
    public void SayHi()
    {
        Console.WriteLine($"你好,我是{Name}");
    }
}

  static void Main(string[] args)
  {
      ServiceCollection services = new ServiceCollection();
      services.AddTransient<TestServiceImpl>();
      using (ServiceProvider sp = services.BuildServiceProvider())
      {
          TestServiceImpl testService = sp.GetRequiredService<TestServiceImpl>();
          testService.Name = "tom";
          testService.SayHi();
      }
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

生命周期

Transient:

static void Main(string[] args)
{
    ServiceCollection services = new ServiceCollection();
    services.AddTransient<TestServiceImpl>();

    using (ServiceProvider sp = services.BuildServiceProvider())
    {
        var ts1 = sp.GetService<TestServiceImpl>();
        var ts2 = sp.GetService<TestServiceImpl>();
        Console.WriteLine(object.ReferenceEquals(ts1, ts2));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

输出:False

Singleton:

static void Main(string[] args)
{
    ServiceCollection services = new ServiceCollection();
    services.AddSingleton<TestServiceImpl>();
    
    using (ServiceProvider sp = services.BuildServiceProvider())
    {
        var ts1 = sp.GetService<TestServiceImpl>();
        var ts2 = sp.GetService<TestServiceImpl>();
        Console.WriteLine(object.ReferenceEquals(ts1, ts2));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

输出:True

Scoped:

 static void Main(string[] args)
 {
     ServiceCollection services = new ServiceCollection();
     services.AddScoped<TestServiceImpl>();
     
     using (ServiceProvider sp = services.BuildServiceProvider())
     {
         using (IServiceScope scope = sp.CreateScope())
         {
             var ts1 = scope.ServiceProvider.GetService<TestServiceImpl>();
             var ts2 = scope.ServiceProvider.GetService<TestServiceImpl>();

             Console.WriteLine(object.ReferenceEquals(ts1, ts2));
         }
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

输出:True

GetServiceGetRequiredService有生命区别?
GetService如果找不到注入的类会返回null,
GetRequiredService如果找不到注入的类会抛出异常。

Tips: 生命周期的选择:如果类无状态,建议为Singleton;如果类有状态,且有Scope控制,建议为Scoped,因为通常这种Scope控制下的代码都是运行在同一个线程中的,没有并发修改的问题;在使用Transient的时候要谨慎。

IServiceProvider的服务定位器方法

  • T GetService<T>() 如果获取不到对象,则返回null。
  • object GetService(Type serviceType)
  • T GetRequiredService<T>()如果获取不到对象,则抛异常
  • object GetRequiredService(Type serviceType)
  • IEnumerable<T> GetServices<T>()适用于可能有很多满足条件的服务
  • IEnumerable<object> GetServices(Type serviceType)

总结:
1、依赖注入是有“传染性”的,如果一个类的对象是通过DI创建的,那么这个类的构造函数中声明的 所有服务类型的参数都会被DI赋值;但是如果一个对象是程序员手动创建的,那么 这个对象就和DI没有关系,它的构造函数中声明的服务类型参数就不会被自动赋值。
2、.NET的DI默认是 构造函数注入
3、第三方DI容器:Autofac等。Autofac优点:支持属性注入、基于名字注入、基于约定的注入等。

配置系统

Json文件配置

1、创建一个json文件,文件名随意,比如config.json,设置“ 如果较新则复制”。
2、NuGet安装Microsoft.Extensions.ConfigurationMicrosoft.Extensions.Configuration.Json
3、
config.json

{
  "exclude": [
    "**/bin",
    "**/bower_components",
    "**/jspm_packages",
    "**/node_modules",
    "**/obj",
    "**/platforms"
  ],
  "name": "yh",
  "age": 18,
  "proxy": {
    "address": "bbaa",
    "port": 80
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
    static void Main(string[] args)
    {
        ConfigurationBuilder configBuilder = new ConfigurationBuilder();
        configBuilder.AddJsonFile(
"config.json", optional: false, reloadOnChange: false);
        IConfigurationRoot config = configBuilder.Build();
        string name = config["name"];
        string proxyAddress = config.GetSection("proxy:address").Value;

        Console.WriteLine(name);
        Console.WriteLine(proxyAddress);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

optional参数:表示这个文件是否可选。初学时,建议optional设置为false,这样写错了的话能够及时发现。
reloadOnChange参数:表示如果文件修改了,是否重新加载配置。

绑定类读取配置

绑定一个类,自动完成配置的读取。

1、NuGet安装:Microsoft.Extensions.Configuration.Binder
2、

static void Main(string[] args)
{
    ConfigurationBuilder configBuilder = new ConfigurationBuilder();
    configBuilder.AddJsonFile(
"config.json", optional: false, reloadOnChange: false);
    IConfigurationRoot configRoot = configBuilder.Build();

    Proxy proxy = configRoot.GetSection("proxy").Get<Proxy>();
    Console.WriteLine(proxy.Address);
    Console.WriteLine(proxy.Port);

    Config config = configRoot.Get<Config>();
    Console.WriteLine(config.Name);
    Console.WriteLine(config.Proxy.Address);
}

 class Config
 {
     public string Name { get; set; }
     public int Age { get; set; }
     public Proxy Proxy { get; set; }
 }
 class Proxy
 {
     public string Address { get; set; }

     public int Port { get; set; }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/290052
推荐阅读
相关标签
  

闽ICP备14008679号