• 循序渐进学.Net Core Web Api开发系列【11】:依赖注入


    原文:循序渐进学.Net Core Web Api开发系列【11】:依赖注入

    系列目录

    循序渐进学.Net Core Web Api开发系列目录

     本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi

    一、概述

    本篇介绍如何采用依赖注入的方式创建和使用对象,主要从应用层面进行描述,不涉及具体的内部原理。

    二、演练

    假设要做一个日志服务的类,它实现在控制台打印出带时间信息的日志信息。

    首先定义该服务的接口与实现类。

    复制代码
       public interface ILogService
        {
            void LogInfomation(string info);
        }
    
    </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span><span style="color: #000000;"> MyLogService : ILogService
    {
        </span><span style="color: #0000ff;">void</span> ILogService.LogInfomation(<span style="color: #0000ff;">string</span><span style="color: #000000;"> info)
        {
            Console.WriteLine($</span><span style="color: #800000;">"</span><span style="color: #800000;"> ==&gt; MyLogService : {DateTime.Now.ToString()}:{info}</span><span style="color: #800000;">"</span><span style="color: #000000;">);
        }
    }</span></pre>
    
    复制代码

    注册该服务

    复制代码
    public void ConfigureServices(IServiceCollection services)
            {
                services.AddMvc();
                services.AddCors();
    
           <span style="color: #ff00ff;">services.AddSingleton</span></span><span style="color: #ff00ff;">&lt;ILogService, MyLogService&gt;</span><span style="color: #000000;"><span style="color: #ff00ff;">();</span>
        }</span></pre>
    
    复制代码

    注册成功,我们在Controller中使用该服务:

    复制代码
    public class ArticleController : Controller
        {       
        private readonly ILogService _myLog;
        </span><span style="color: #0000ff;">public</span> ArticleController(<span style="color: #000000;"><span style="color: #ff00ff;">ILogService myLog</span>)
        { </span><span style="color: #000000;">
            _myLog </span>=<span style="color: #000000;"> myLog;
        }        
    
        [HttpGet(</span><span style="color: #800000;">"</span><span style="color: #800000;">logger</span><span style="color: #800000;">"</span><span style="color: #000000;">)]
        </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> TestLogger(<span style="color: #0000ff;">string</span><span style="color: #000000;"> logger)
        {
            _myLog.LogInfomation(</span><span style="color: #800000;">"</span><span style="color: #800000;">hahaha</span><span style="color: #800000;">"</span><span style="color: #000000;">);
            </span><span style="color: #0000ff;">return</span><span style="color: #000000;">;
        }
    }</span></pre>
    
    复制代码

     简单分析一下:

    1、首先通过services.AddSingleton方法向依赖注入容器登记注册MyLogService;

    2、在构建Controller时,根据其构造函数类型遍历其输入参数,在依赖注入容器中找到该对象并作为实参传递给构造方法。

    三、生命周期问题

    注册一个服务,根据生命周期需要的不同,有下面三种方式:

    1
    2
    3
    4
    5
    services.AddSingleton<ILogService, MyLogService>();
     
    services.AddScoped<ILogService, MyLogService>();
     
    ervices.AddTransient<ILogService, MyLogService>();

    三种注册方式分别对应三种生命周期

    1)Singleton:单例服务,从当前服务容器中获取这个类型的实例永远是同一个实例;

    2)Scoped:每个作用域生成周期内创建一个实例;

    3)Transient:每一次请求服务都创建一个新实例;

    对我们的日志进行改造,让其在构建时生成一个ID,通过观察其guid变化可以理解这三种生命周期的区别。

    复制代码
    public class MyLogService : ILogService
        {
            public  Guid _guid;
    
        </span><span style="color: #0000ff;">public</span><span style="color: #000000;"> MyLogService()
        {
            _guid </span>=<span style="color: #000000;"> Guid.NewGuid();
        }
    
        </span><span style="color: #0000ff;">void</span> ILogService.LogInfomation(<span style="color: #0000ff;">string</span><span style="color: #000000;"> info)
        {
            Console.WriteLine($</span><span style="color: #800000;">"</span><span style="color: #800000;"> ==&gt; MyLogService : My Guid is :{_guid}</span><span style="color: #800000;">"</span><span style="color: #000000;">);
            Console.WriteLine($</span><span style="color: #800000;">"</span><span style="color: #800000;"> ==&gt; MyLogService : {DateTime.Now.ToString()}:{info}</span><span style="color: #800000;">"</span><span style="color: #000000;">);
        }
    }</span></pre>
    
    复制代码

    四、通过扩展方法注册服务

    通过对IServiceCollection增加扩展方法来注册服务

    复制代码
    public static class MyLogServiceCollectionExtensions
        {
            public static void AddMyLog(this IServiceCollection services)
            {
                services.AddSingleton<ILogService, MyLogService>();
            }
        }
    复制代码

    这样,使用者的注册代码可以修改为:

    public void ConfigureServices(IServiceCollection services)
    {   
      services.AddMvc();
      services.AddCors();
      services.AddMyLog(); 
    }

    可见AddMvc、AddCors等也是向容器注入服务。

    复制代码
            public static IMvcBuilder AddMvc(this IServiceCollection services)
            {
                if (services == null)
                {
                    throw new ArgumentNullException("services");
                }
                IMvcCoreBuilder mvcCoreBuilder = MvcCoreServiceCollectionExtensions.AddMvcCore(services);
                MvcApiExplorerMvcCoreBuilderExtensions.AddApiExplorer(mvcCoreBuilder);
                MvcCoreMvcCoreBuilderExtensions.AddAuthorization(mvcCoreBuilder);
                MvcServiceCollectionExtensions.AddDefaultFrameworkParts(mvcCoreBuilder.PartManager);
                MvcCoreMvcCoreBuilderExtensions.AddFormatterMappings(mvcCoreBuilder);
                MvcViewFeaturesMvcCoreBuilderExtensions.AddViews(mvcCoreBuilder);
                MvcRazorMvcCoreBuilderExtensions.AddRazorViewEngine(mvcCoreBuilder);
                MvcRazorPagesMvcCoreBuilderExtensions.AddRazorPages(mvcCoreBuilder);
                TagHelperServicesExtensions.AddCacheTagHelper(mvcCoreBuilder);
                MvcDataAnnotationsMvcCoreBuilderExtensions.AddDataAnnotations(mvcCoreBuilder);
                MvcJsonMvcCoreBuilderExtensions.AddJsonFormatters(mvcCoreBuilder);
                MvcCorsMvcCoreBuilderExtensions.AddCors(mvcCoreBuilder);
                return new MvcBuilder(mvcCoreBuilder.Services, mvcCoreBuilder.PartManager);
            }
    复制代码

    五、几个问题

    1、如果多次注册会怎样

    可以多次注册同一种生命周期的类,如下是可以的:

    services.AddSingleton<ILogService, MyLogService>();
    services.AddSingleton<ILogService, MyLogService>();
    services.AddSingleton<ILogService, MyLogService>();

    但下面这个代码不行:

    services.AddSingleton<ILogService, MyLogService>();
    services.AddScoped<ILogService, MyLogService>();

    2、如何获取已经注册的服务列表

    通过ServicesProvider可以获取服务列表

    复制代码
                services.AddMyLog();
                services.AddMyLog();
                services.AddMyLog();
    
            </span><span style="color: #0000ff;">var</span> provider =<span style="color: #000000;"> services.BuildServiceProvider();
            </span><span style="color: #0000ff;">var</span> servicesList = provider.GetServices&lt; ILogService &gt;<span style="color: #000000;">();
            </span><span style="color: #0000ff;">foreach</span> (<span style="color: #0000ff;">var</span> service <span style="color: #0000ff;">in</span><span style="color: #000000;"> servicesList)
            {
                Console.WriteLine(</span><span style="color: #800000;">"</span><span style="color: #800000;">service:</span><span style="color: #800000;">"</span> +<span style="color: #000000;"> service.ToString());
            }</span></pre>
    
    复制代码

    以上代码输出3条记录。

    但下面的代码只输出一条记录:

    复制代码
                services.AddCors();
                services.AddCors();
                services.AddCors();          
    
            </span><span style="color: #0000ff;">var</span> provider =<span style="color: #000000;"> services.BuildServiceProvider();
            </span><span style="color: #0000ff;">var</span> servicesList = provider.GetServices&lt;ICorsService&gt;<span style="color: #000000;">();
            </span><span style="color: #0000ff;">foreach</span> (<span style="color: #0000ff;">var</span> service <span style="color: #0000ff;">in</span><span style="color: #000000;"> servicesList)
            {
                Console.WriteLine(</span><span style="color: #800000;">"</span><span style="color: #800000;">service:</span><span style="color: #800000;">"</span> +<span style="color: #000000;"> service.ToString());
            }</span></pre>
    
    复制代码

    具体原因看一下源码就清楚了:

    复制代码
    public static IServiceCollection AddCors(this IServiceCollection services)
    {
        if (services == null)
        {
            throw new ArgumentNullException("services");
        }
        services.TryAdd(ServiceDescriptor.Transient<ICorsService, CorsService>());
        return services;
    }
        public static void TryAdd(this IServiceCollection collection, ServiceDescriptor descriptor)
         {
                if (!collection.Any((ServiceDescriptor d) => d.ServiceType == descriptor.ServiceType))
                {
                    collection.Add(descriptor);
                }
         }
    复制代码

    所以我们应该按照这个方法修改我们的AddMyLog方法。

  • 相关阅读:
    Linux学习之路:shell变量(二)环境变量
    LVS配置与安装
    Linux学习之路:shell变量(一)
    SQL Server用存储过程新建视图
    【转】SQL Server 2012 配置AlwaysOn(三)
    【转】SQL 语句:Alter table
    Linux学习之路:认识shell和bash
    【转】Centos配置yum源
    【Azure 应用服务】App Service 无法连接到Azure MySQL服务,报错:com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
    【Azure API 管理】在APIM 中添加 logtoeventhub 策略,把 Request Body 信息全部记录在Event Hub中
  • 原文地址:https://www.cnblogs.com/owenzh/p/11206823.html
Copyright © 2020-2023  润新知