zoukankan      html  css  js  c++  java
  • 循序渐进学.Net Core Web Api开发系列【11】:依赖注入

    系列目录

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

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

    一、概述

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

    二、演练

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

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

       public interface ILogService
        {
            void LogInfomation(string info);
        }
    
        public class MyLogService : ILogService
        {
            void ILogService.LogInfomation(string info)
            {
                Console.WriteLine($" ==> MyLogService : {DateTime.Now.ToString()}:{info}");
            }
        }

    注册该服务

    public void ConfigureServices(IServiceCollection services)
            {
                services.AddMvc();
                services.AddCors();
    
               services.AddSingleton<ILogService, MyLogService>();
            }

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

    public class ArticleController : Controller
        {       
        private readonly ILogService _myLog; public ArticleController(ILogService myLog) { _myLog = myLog; } [HttpGet("logger")] public void TestLogger(string logger) { _myLog.LogInfomation("hahaha"); return; } }

     简单分析一下:

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

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

    三、生命周期问题

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

    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;
    
            public MyLogService()
            {
                _guid = Guid.NewGuid();
            }
    
            void ILogService.LogInfomation(string info)
            {
                Console.WriteLine($" ==> MyLogService : My Guid is :{_guid}");
                Console.WriteLine($" ==> MyLogService : {DateTime.Now.ToString()}:{info}");
            }
        }

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

    通过对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);
            }
    View Code

    五、几个问题

    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();
    
                var provider = services.BuildServiceProvider();
                var servicesList = provider.GetServices< ILogService >();
                foreach (var service in servicesList)
                {
                    Console.WriteLine("service:" + service.ToString());
                }

    以上代码输出3条记录。

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

                services.AddCors();
                services.AddCors();
                services.AddCors();          
    
                var provider = services.BuildServiceProvider();
                var servicesList = provider.GetServices<ICorsService>();
                foreach (var service in servicesList)
                {
                    Console.WriteLine("service:" + service.ToString());
                }

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

    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方法。

  • 相关阅读:
    Generate Parentheses (Java)
    leetcode15
    MD5
    leetcode409
    Vue第一个简单的例子
    SpringBoot和Ajax通信
    如何使用安装光盘为本机创建yum repository
    Less known Solaris features: svccfg editprop (ZT)
    Rename Oracle Managed File (OMF) datafiles in ASM(ZT)
    跨数据文件删除flashback database
  • 原文地址:https://www.cnblogs.com/seabluescn/p/9323817.html
Copyright © 2011-2022 走看看