循序渐进学.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方法。

 

0
0
« 上一篇:循序渐进学.Net Core Web Api开发系列【4】:前端访问WebApi
» 下一篇:循序渐进学.Net Core Web Api开发系列【14】:异常处理
</div>
posted @ 2019-07-18 13:49  奋斗的中年人哈哈哈  阅读(324)  评论(0编辑  收藏  举报