系列目录

循序渐进学.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);
}

五、几个问题

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

循序渐进学.Net Core Web Api开发系列【11】:依赖注入的更多相关文章

  1. 循序渐进学.Net Core Web Api开发系列【0】:序言与目录

    一.序言 我大约在2003年时候开始接触到.NET,最初在.NET framework 1.1版本下写过代码,曾经做过WinForm和ASP.NET开发.大约在2010年的时候转型JAVA环境,这么多 ...

  2. 循序渐进学.Net Core Web Api开发系列【16】:应用安全续-加密与解密

    系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 应用安全除 ...

  3. 循序渐进学.Net Core Web Api开发系列【15】:应用安全

    系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍W ...

  4. 循序渐进学.Net Core Web Api开发系列【14】:异常处理

    系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍异 ...

  5. 循序渐进学.Net Core Web Api开发系列【13】:中间件(Middleware)

    系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍如 ...

  6. 循序渐进学.Net Core Web Api开发系列【12】:缓存

    系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍如 ...

  7. 循序渐进学.Net Core Web Api开发系列【10】:使用日志

    系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.本篇概述 本篇介 ...

  8. 循序渐进学.Net Core Web Api开发系列【9】:常用的数据库操作

    系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇描述一 ...

  9. 循序渐进学.Net Core Web Api开发系列【8】:访问数据库(基本功能)

    系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇讨论如 ...

随机推荐

  1. opencv ---getRotationMatrix2D函数

    getRotationMatrix2D函数 主要用于获得图像绕着 某一点的旋转矩阵  Mat getRotationMatrix2D(Point2f center, double angle, dou ...

  2. adb logcat介绍

    logcat命令语法: [adb] logcat [<option>] ... [<filter-spec>] ... adb logcat -c 清除所有以前的日志 adb ...

  3. 烦人的IE7、8,半透明滤镜(filter:alpha)失效、png半透明失效的解决办法

    在项目中的问题,之前用的是用IETest测试IE7,8发现背景透明设置无效,后来找文章解决!看了一些资料,做下总结. 几种IE半透明CSS样式 IE8里可以这样写 -ms-filter:”progid ...

  4. C语言复习---选择法排序

    选择排序也是一种简单直观的排序算法 它的工作原理很容易理解:初始时在序列中找到最小(大)元素,放到序列的起始位置作为已排序序列:然后,再从剩余未排序元素中继续寻找最小(大)元素,放到已排序序列的末尾. ...

  5. Java迭代器用法

    public class Test01 { public static void main(String[] args) { List list = new ArrayList(); list.add ...

  6. ant+sonar+jacoco代码质量代码覆盖率扫描

    使用ant构建的java web项目如何做sonar代码质量扫描?以下就是实际遇到并成功使用的案例一.做sonar扫描的准备工作    1.给web项目增加build.xml构建脚本.    2.下载 ...

  7. python3光学字符识别模块tesserocr与pytesseract

    OCR,即Optical Character Recognition,光学字符识别,是指通过扫描字符,然后通过其形状将其翻译成电子文本的过程,对应图形验证码来说,它们都是一些不规则的字符,这些字符是由 ...

  8. python进阶之魔法函数

    __repr__ Python中这个__repr__函数,对应repr(object)这个函数,返回一个可以用来表示对象的可打印字符串.如果我们直接打印一个类,向下面这样 class A():     ...

  9. phantomjs waitFor

    function waitFor(testFx, onReady, timeOutMillis) { var maxtimeOutMillis = timeOutMillis ? timeOutMil ...

  10. rank over partition by

    高级函数,分组排序 over: 在什么条件之上. partition by e.deptno: 按部门编号划分(分区). order by e.sal desc: 按工资从高到低排序(使用rank() ...