• Microsoft.Extensions 简介


    Microsoft.Extensions 简介

    一、Microsoft.Extensions 简介

    .NET Extensions 是一套官方的、开源的、跨平台的 API 集合,提供了一些常用的编程模式和实用工具,例如依赖项注入、日志记录、缓存、Host以及配置等等。该项目的大多数 API 都被用在 .NET 平台的各个应用框架上,如 http://ASP.NET Core,Xamarin 等等。虽然 http://ASP.NET 使用了很多这些 API 但 http://ASP.NET 并没有与它们紧密耦合。你也可以在控制台应用程序、WinForm以及WPF应用程序上使用它们。总结一句就是:它是官方造的“轮子”

    **

    NET API browser 中的 .NET Platform Extensions
    .NET Platform Extensions 包括下面所列的包,由于 .NET 5 正在整合各个代码仓库,所以 .NET Extension 中的部分代码仓库已经分别以迁移到了 dotnet/runtime 和 dotnet/aspnetcore 这两个仓库中。
    
    ## 移动到 dotnet/runtime 的包:
    
    ## **Caching**
    
    Microsoft.Extensions.Caching.Abstractions
    Microsoft.Extensions.Caching.Memory
    
    ## Configuration
    
    Microsoft.Extensions.Configuration
    Microsoft.Extensions.Configuration.Abstractions
    Microsoft.Extensions.Configuration.Binder
    Microsoft.Extensions.Configuration.CommandLine
    Microsoft.Extensions.Configuration.EnvironmentVariables
    Microsoft.Extensions.Configuration.FileExtensions
    Microsoft.Extensions.Configuration.Ini
    Microsoft.Extensions.Configuration.Json
    Microsoft.Extensions.Configuration.UserSecrets
    Microsoft.Extensions.Configuration.Xml
    
    ## Dependency Injection
    
    Microsoft.Extensions.DependencyInjection
    Microsoft.Extensions.DependencyInjection.Abstractions
    
    ## File Providers
    
    Microsoft.Extensions.FileProviders.Abstractions
    Microsoft.Extensions.FileProviders.Composite
    Microsoft.Extensions.FileProviders.Physical
    File System Globbing
    Microsoft.Extensions.FileSystemGlobbing
    
    ## Hosting
    
    Microsoft.Extensions.Hosting
    Microsoft.Extensions.Hosting.Abstractions
    Http Client Factory
    Microsoft.Extensions.Http
    
    ## Logging
    
    Microsoft.Extensions.Logging
    Microsoft.Extensions.Logging.Abstractions
    Microsoft.Extensions.Logging.Configuration
    Microsoft.Extensions.Logging.Console
    Microsoft.Extensions.Logging.Debug
    Microsoft.Extensions.Logging.EventLog
    Microsoft.Extensions.Logging.EventSource
    Microsoft.Extensions.Logging.Testing
    Microsoft.Extensions.Logging.TraceSource
    
    ## Options
    
    Microsoft.Extensions.Options
    Microsoft.Extensions.Options.ConfigurationExtensions
    Microsoft.Extensions.Options.DataAnnotations
    
    ## Primitives
    
    Microsoft.Extensions.Primitives
    
    ## 移动到 dotnet/aspnetcore 的包:
    
    ## Configuration
    
    Microsoft.Extensions.Configuration.KeyPerFile
    
    ## File Providers
    
    Microsoft.Extensions.FileProviders.Embedded
    Microsoft.Extensions.FileProviders.Embedded.Manifest.Task
    
    ## Health Checks
    
    Microsoft.Extensions.Diagnostics.HealthChecks
    Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions
    
    ## JS Interop
    
    Microsoft.JSInterop
    Mono.WebAssembly.Interop
    
    ## Localization
    
    Microsoft.Extensions.Localization
    Microsoft.Extensions.Localization.Abstractions
    
    ## Logging
    
    Microsoft.Extensions.Logging.AzureAppServices
    
    ## Object Pool
    
    Microsoft.Extensions.ObjectPool
    Web Encoders
    Microsoft.Extensions.WebEncoders
    
    ## 目前仍在 dotnet/extensions 的包:
    
    ## Caching
    
    Microsoft.Extensions.Caching.SqlServer
    Microsoft.Extensions.Caching.StackExchangeRedis
    
    ## Configuration
    
    Microsoft.Extensions.Configuration.NewtonsoftJson
    
    ## Hosting
    
    Microsoft.Extensions.Hosting.Systemd
    Microsoft.Extensions.Hosting.WindowsServices
    
    ## Http Client Factory
    
    Microsoft.Extensions.Http.Polly
    
    ## Logging
    
    Microsoft.Extensions.Logging.Analyzers (has not been released to NuGet.org as of writing)
    Microsoft.Extensions.DependencyInjection.Specification.Tests
    
    
    
    • 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
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127

    二、什么是依赖注入?

    **
    依赖注入,字面理解就是将依赖注入到你的代码中,那么为什么需要将依赖注入到你的代码中呢?以及怎么注入到你的代码?下面我们来一步一步来了解整个过程。
    1)首先,通常情况下当我们要使用另外一个类型时我们会使用下面的代码来生成一个该类型的实例。

    var a = new ClassA();
    a.MehtodA();
    
    • 1
    • 2

    此时相当于我们的代码依赖了ClassA,一旦 ClassA 发生了改变我们的代码也就需要发生相应的改变,这不符合松耦合的设计原则,那么我们应该怎么做呢?

    2)为了让我们的代码不直接依赖于 ClassA 我们来定义一个接口 InterfaceA,

    interface InterfaceA
    {
        void MethodA();
    }
    
    • 1
    • 2
    • 3
    • 4

    并让== ClassA 实现该接口==,那么我们就可以这样写我们的代码了,

    InterfaceA a = new ClassA();
    a.MethodA();
    
    • 1
    • 2

    此时我们的代码本质上是对 InterfaceA 的依赖,并不关心 InterfaceA 的具体实现。不过目前好像没什么鸟用,因为我们的代码中仍然需要显式实例化 ClassA这时候我们就希望能有一个神奇的工具能给我们一个 InterfaceA 的实例了。

    3)现在 IoC 容器就闪亮登场了(IoC, Inversion of Control / 控制反转),它可以使用多种方式给我们的代码中注入我所需要的 InterfaceA 实例,下面的代码就是利用构造函数注入依赖。

    public class MyCode
    {
        private InterfaceA _ia;
     
        public MyCode(InterfaceA ia)
        {
            _ia = ia;
        }
     
        public void MyMethod()
        {
            _ia.MethodA();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    这样在我们的代码里就看不到 ClassA 了,我们的代码也就脱离了对 ClassA的依赖,实现了松耦合,也践行了部分面向对象的设计原则,如依赖倒置(DIP)原则。

    下面我们使用 Microsoft.Extensions 中的 DependencyInjection 容器(在下文中我们简称为DI容器)来实现上面示例的完整代码。

    using System;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.DependencyInjection.Extensions;
     
    namespace DemoCode
    {
        class Program
        {
            static void Main(string[] args)
            {
                //初始化容器
                IServiceCollection ioc = new ServiceCollection();
                //这里的是添加服务到容器中
                //Transient指的是服务实例的生命周期,即每次请求服务的时候都会创建一个新的实例
                ioc.TryAddTransient<MyCode>();
                ioc.TryAddTransient<InterfaceA, ClassA>();
     
                //创建serviceProvider对象来获取服务的实例
                var serviceProvider = ioc.BuildServiceProvider();
                var myCodeinstance = serviceProvider.GetService<MyCode>();
     
                //调用我们定义的方法
                myCodeinstance .Run();
            }
        }
     
        //
        public class MyCode
        {
            private InterfaceA _ia;
            public MyCode(InterfaceA ia)
            {
                _ia = ia;
            }
     
            public void Run()
            {
                _ia.MethodA();
            }
        }
     
        //定义服务的接口
        public interface InterfaceA
        {
            void MethodA();
        }
     
        //服务的具体实现
        public class ClassA : InterfaceA
        {
            public void MethodA()
            {
                Console.WriteLine("MethodA 被调用");
            }
        }
    }
    
    • 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
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    依赖注入以及控制反转都属于设计模式(Design Pattern),并且通常情况下,要实现控制反转就需要基于依赖注入。它们都是为了遵从面向对象语言的设计原则 S.O.L.I.D 而产生的。

    S: Single responsibility / 单一职责
    O: Open closed / 开闭原则(对扩展开放,对修改关闭)
    L: Liskov substitution / 里氏替换
    I: Interface segregation / 接口分离
    D: Dependency inversion / 依赖倒置
    关于S.O.L.I.D 的更多内容可以查看下面这篇文章,

    S.O.L.I.D: The First 5 Principles of Object Oriented Design​scotch.io
    在这里插入图片描述

    三、DI容器的使用方法

    1、引用

    Microsoft.Extensions.DependencyInjection.Abstractions
    Microsoft.Extensions.DependencyInjection
    这两个包含了容器的抽象以及容器的具体实现,其中Microsoft.Extensions.DependencyInjection.Abstractions 为抽象,Microsoft.Extensions.DependencyInjection 则为具体实现。

    当你要在自己的程序中使用时,使用nuget包管理工具安装 Microsoft.Extensions.DependencyInjection 包即可。
    2、主要类型

    1、引用类型
    使用 DI 容器需要熟悉下面的接口与类型,Microsoft.Extensions.DependencyInjection.IServiceCollection,该接口包含了一系列 Add 扩展方法来添加你的服务,该接口的默认实现为 Microsoft.Extensions.DependencyInjection.ServiceCollection 类。

    容器接口叫做 IServiceCollection 是因为 “微软”将容器中的类型视为我们程序所需的服务,有了这个前提将它命名为 “ServiceCollection”也就非常合理了。

    System.IServiceProvider,使用 IServiceCollection 的扩展方法 BuildServiceProvider() 可以得到一个默认的 ServiceProvider 对象来让我们获取服务实例,ServiceProvider 实现了IServiceProvider 接口,该接口包含了一个 GetService() 方法来获取服务。IServiceProvider 接口的默认实现为 Microsoft.Extensions.DependencyInjection.ServiceProvider 类。
    2、IServiceCollection,添加服务与生命周期

    IServiceCollection 接口包含一系列的扩张方法让我们方便的添加服务,常用的包括下面三个方法,

    1. AddTransient,添加生命周期为Transient(短暂)的服务,这样的服务在每次被请求是都会创建一个新的实例
    2. AddSingleton
      ,添加生命周期为Singleton(单例)的服务,这样的服务只有在首次请求是创建一个新的实例,之后都会使用这个实例
    3. AddScoped,添加生命周期为Scoped(域内)的服务,这样的服务在一个自定义的“作用域”范围内是单例的。例如,在
      http://ASP.NET Core 中 Scoped 服务在每一次请求中都是一个实例。 除此之外你也可以使用 Add 方法,并使用
      ServiceLifetime 在参数中指定生命周期。

    除了上面这三个常用方法之外,还有 TryAddTransient、TryAddSingleton、TryAddScoped 这三个用于添加服务的方法,与之前所提三个方法的区别在于带 Try 的这三个方法在添加服务时会检查服务是否已存在,若已经存在则不再添加。
    3、IServiceProvider,获取服务与注入依赖
    你可以使用 IServiceCollection 的 BuildServiceProvider() 方法来获取 IServiceProvider 对象,使用 GetServices 方法便可以获取你添加到容器中的服务,对于 Transient 和 Singleton 的服务使用这个方法便可以实现其对应的生命周期逻辑。

    Scoped的情况相对有点复杂,如果你直接使用 IServiceProvider 的 GetServices()方法获取服务那么Scoped 服务的行为就和 Singleton 是一样的,它的的生命周期和 IServiceProvider 对象是一致的,下面的代码演示了如何使用 ScopedService,

    
    //在using的作用域内scopeService是单例的
    //在创建新的Scope之后,容器会创建新的scopedService实例
    using (var scope = serviceProvider.CreateScope())
    {
        var scopedServiceProvider = scope.ServiceProvider;
        var myScopedService = scopedServiceProvider.GetService<IMyScopedService>();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    除了使用容器直接获取服务,我们还需要了解容器的注入方式,ioc容器的注入通常有三种方法

    1. 构造函数注入,在构造函数中将服务已参数的方式注入到类中。
    2. 方法注入,通过指定的方法将服务实例传入类中。
    3. 属性注入,通过设置实例到属性将服务实例注入到类中。DI 容器暂不支持该注入方式。

    构造函数注入在上面已经演示了,下面是 http://ASP.NET Core 自定义Middleware 中方法注入的示例代码,

    public class CustomMiddleware
    {
        private readonly RequestDelegate _next;
     
        public CustomMiddleware(RequestDelegate next)
        {
            _next = next;
        }
     
        //在Invoke方法中,将IMyScopedService服务注入到类中。
        public async Task Invoke(HttpContext httpContext, IMyScopedService svc)
        {
            svc.MyProperty = 1000;
            await _next(httpContext);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    四、在 http://ASP.NET Core 中替换容器实现

    DI 容器相对于其他第三方更加成熟的 IoC 容器来说,功能并不是十分完善,下面是 DI 容器暂时不支持的功能。

    • 属性注入
    • 基于名称的注入
    • 子容器
    • 自定义的生命周期管理
    • 支持 Func 的延迟初始化
    • 基于约定的注册

    不过在 DI 容器能满足你需求的情况下,微软还是建议使用该容器。 如果它不能满足你的需求,你可以选择下面推荐的第三方 IoC 容器。

    • Autofac
    • DryIoc
    • Grace
    • LightInject
    • Lamar
    • Stashbox
    • Unity

    不过在 http://ASP.NET Core 中情况比较特殊,由于 http://ASP.NET Core 是基于 DI 容器的,所以要在http://ASP.NET Core 中使用其他容器,就需要替换 IServiceProvider 的实现。下面的代码展示的是如何在 http://ASP.NET Core 中集成 Autofac 容器。

    
    public class Program
    {
      public static void Main(string[] args)
      {
        // 适用于ASP.NET Core 3.0+:
        var host = Host.CreateDefaultBuilder(args)
            .UseServiceProviderFactory(new AutofacServiceProviderFactory())
            .ConfigureWebHostDefaults(webHostBuilder => {
              webHostBuilder
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseIISIntegration()
                .UseStartup<Startup>();
            })
            .Build();
     
        host.Run();
      }
     }
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
  • 相关阅读:
    YOLOv6 | 模型结构与训练策略详细解析
    精品基于NET实现的论坛管理系统
    vscode c++食用指南
    FFmpeg开发笔记(十八)FFmpeg兼容各种音频格式的播放
    配置文件自动提示
    体系班第十三节
    Chrome 使用
    react嵌套路由
    Java中Spring AOP讲解
    习题6-3 使用函数输出指定范围内的完数 (20分)
  • 原文地址:https://blog.csdn.net/kalvin_y_liu/article/details/118613330