4. ASP.NET Core默认服务

之前讲了中间件,实际上一个中间件要正常进行工作,通常需要许多的服务配合进行,而中间件中的服务自然也是通过 Ioc 容器进行注册和注入的。前面也讲到,按照约定中间件的封装一般会提供一个 User{Middleware} 的扩展方法给用户使用,而服务注册中也有一个类似的约定,一般会有一个 Add{Services} 的扩展方法。

例如一个WebApi项目中,对于控制器路由终结点中间件的配置使用:

builder.Services.AddControllers();

var app = builder.Build();
app.MapControllers();

这也是我们在日常开发中可以学习的方式,随着业务增长,需要依赖注入的服务也越来越多,我们可以根据业务模块,通过扩展方法讲相应模块的服务注入注册进行封装,命名为 Add{Services},更加清晰明了地对我们的业务进行封装。

.NET Core 框架下默认提供250个以上的的服务,包括 ASP.NET Core MVC、EF Core 等等,当然这些服务很多不会默认就注入到容器中,我们在新建一个项目的时候,不同项目框架的模板会帮我们默认配置好一些最基本的必须的服务,其他的服务我们可以根据自己的需要进行使用。

5. 依赖注入配置变形

随着业务的增长,我们项目工作中的类型、服务越来越多,而每一个服务的依赖注入关系都需要在入口文件通过Service.Add{}方法去进行注册,这将是非常麻烦的,入口文件需要频繁改动,而且代码组织管理也会变得麻烦,非常不优雅。

在许多框架中会对这种通过 Service.Add{xxx} 的方式在代码中显式注册依赖注入关系的方式进行变形,有的可以通过配置文件进行注册,例如 Java Spring 框架就有这样大量的配置文件,有的可以通过接口进行默认注册,有的通过特性进行默认注册。

这里稍微简单介绍一下依赖注入默认注册的原理,其实也就是通过放射的一些手段,再加上一些约定好的规则而已。

首先需要三个生命周期接口,如下,这三个接口没有内容,仅仅只是作为标记而已。

public interface ISingleton
{
}
public interface IScoped
{
}
public interface ITransient
{
}

之后需要一个扩展方法,如下:

namespace Microsoft.Extensions.DependencyInjection
{
public static class ServiceCollectionDependencyExtensions
{
public static IServiceCollection AddAutoInject<T>(this IServiceCollection services)
{
var register = new ServiceRegister();
register.AddAssembly(services, typeof(T).Assembly);
return services;
}
}
}

这个扩展方法中调用了注册器,往容器中注入服务,实现如下:

public class ServiceRegister
{
public void AddAssembly(IServiceCollection services, Assembly assembly)
{
// 查找程序中的类型
var types = assembly.GetTypes().Where(t => t != null && t.IsClass && !t.IsAbstract && !t.IsGenericType);
// 遍历每一个类检查释放满足约定的规则
foreach (var type in types)
{
AddType(services, type);
}
} /// <summary>
/// 添加当前类型的依赖注入关系
/// </summary>
/// <param name="services"></param>
/// <param name="type"></param>
public void AddType(IServiceCollection services, Type type)
{
var lifetime = GetLifetimeOrNull(type);
if (lifetime == null)
{
return; var exposeServices = ExposeService(type);
foreach (var serviceType in exposeServices)
{
var serviceDescriptor = new ServiceDescriptor(serviceType, type, lifetime.Value);
services.Add(serviceDescriptor);
}
} /// <summary>
/// 根据标记接口确定生命周期,如果没有添加标记接口的,则不会被自动注册到容器
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public ServiceLifetime? GetLifetimeOrNull(Type type)
{
if (typeof(ISingleton).IsAssignableFrom(type))
{
return ServiceLifetime.Singleton;
}
if(typeof(IScoped).IsAssignableFrom(type))
{
return ServiceLifetime.Scoped;
}
if(typeof(ITransient).IsAssignableFrom(type))
{
return ServiceLifetime.Transient;
}
return null;
}
/// <summary>
/// 根据约定的规则查找当前类对于的服务类型
/// 通过接口实现的方式,查找当前类实现的接口,如果一个接口名称去除了 "I" 之后与当前类的后半段一样,
/// 则当前类应该被注册为这个接口的服务。
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public IList<Type> ExposeService(Type type)
{
var serviceTypes = new List<Type>();
var interfaces = type.GetInterfaces();
foreach (var interfacesType in interfaces)
{
var interfaceName = interfacesType.Name;
if (interfaceName.StartsWith("I"))
{
interfaceName = interfaceName.Substring(1);
}
if (type.Name.EndsWith(interfaceName))
{
serviceTypes.Add(interfacesType);
}
}
return serviceTypes;
}
}

整体的逻辑就是查找遍历程序集中的所有类型,并通过判别类型是否实现之前定好的三个生命周期接口,从而确定类型是否需要自动注册到容器中,如果需要再根据约定好的规则获取需要注册的服务类型,并且构建服务描述器,再将其添加到容器中。

之后在入口文件中这样使用:

builder.Services.AddAutoInject<Program>();

而需要自动注入的服务只要多实现一个标记接口即可:

public class Rabbit : IRabbit, ITransient
{
}

以上主要介绍一下依赖注入自动化注册的思路和基本实现,代码只是一个基本的演示,比较简单,很多细节也没有在这里体现,但是核心的思路是和ABP框架中的自动注入的方式一样的,有兴趣详细了解一下ABP中的依赖注入的机制的童鞋,可以看一下我其他的文章: ABP 依赖注入(1)

参考文章:

ASP.NET Core 依赖注入 | Microsoft Learn

理解ASP.NET Core - 依赖注入(Dependency Injection)

ASP.NET Core 系列:

目录:ASP.NET Core 系列总结

上一篇:ASP.NET Core - 依赖注入(三)

ASP.NET Core - 依赖注入(四)的更多相关文章

  1. # ASP.NET Core依赖注入解读&使用Autofac替代实现

    标签: 依赖注入 Autofac ASPNETCore ASP.NET Core依赖注入解读&使用Autofac替代实现 1. 前言 2. ASP.NET Core 中的DI方式 3. Aut ...

  2. 实现BUG自动检测 - ASP.NET Core依赖注入

    我个人比较懒,能自动做的事绝不手动做,最近在用ASP.NET Core写一个项目,过程中会积累一些方便的工具类或框架,分享出来欢迎大家点评. 如果以后有时间的话,我打算写一个系列的[实现BUG自动检测 ...

  3. [译]ASP.NET Core依赖注入深入讨论

    原文链接:ASP.NET Core Dependency Injection Deep Dive - Joonas W's blog 这篇文章我们来深入探讨ASP.NET Core.MVC Core中 ...

  4. asp.net core 依赖注入几种常见情况

    先读一篇注入入门 全面理解 ASP.NET Core 依赖注入, 学习一下基本使用 然后学习一招, 不使用接口规范, 直接写功能类, 一般情况下可以用来做单例. 参考https://www.cnblo ...

  5. ASP.NET Core依赖注入——依赖注入最佳实践

    在这篇文章中,我们将深入研究.NET Core和ASP.NET Core MVC中的依赖注入,将介绍几乎所有可能的选项,依赖注入是ASP.Net Core的核心,我将分享在ASP.Net Core应用 ...

  6. 自动化CodeReview - ASP.NET Core依赖注入

    自动化CodeReview系列目录 自动化CodeReview - ASP.NET Core依赖注入 自动化CodeReview - ASP.NET Core请求参数验证 我个人比较懒,能自动做的事绝 ...

  7. ASP.NET Core 依赖注入最佳实践——提示与技巧

    在这篇文章,我将分享一些在ASP.NET Core程序中使用依赖注入的个人经验和建议.这些原则背后的动机如下: 高效地设计服务和它们的依赖. 预防多线程问题. 预防内存泄漏. 预防潜在的BUG. 这篇 ...

  8. ASP.NET Core依赖注入最佳实践,提示&技巧

    分享翻译一篇Abp框架作者(Halil İbrahim Kalkan)关于ASP.NET Core依赖注入的博文. 在本文中,我将分享我在ASP.NET Core应用程序中使用依赖注入的经验和建议. ...

  9. ASP.NET Core依赖注入解读&使用Autofac替代实现【转载】

    ASP.NET Core依赖注入解读&使用Autofac替代实现 1. 前言 2. ASP.NET Core 中的DI方式 3. Autofac实现和自定义实现扩展方法 3.1 安装Autof ...

  10. ASP.NET Core 依赖注入基本用法

    ASP.NET Core 依赖注入 ASP.NET Core从框架层对依赖注入提供支持.也就是说,如果你不了解依赖注入,将很难适应 ASP.NET Core的开发模式.本文将介绍依赖注入的基本概念,并 ...

随机推荐

  1. python爬虫爬取网易云音乐(超详细教程,附源码)

    一. 前言 先说结论,目前无法下载无损音乐,也无法下载vip音乐. 此代码模拟web网页js加密的过程,向api接口发送参数并获取数据,仅供参考学习,如果需要下载网易云音乐,不如直接在客户端下载,客户 ...

  2. 解决PC 拖动浏览器或者应用时CPU占用过高问题

    电脑配置5800X.6800XT.win11在用edge或chrome只打开百度和博客园首页的情况下,长按来回拖动浏览器窗口,会发现CPU占用直线上升.能直接从4%变成70-80%导致系统卡住...我 ...

  3. 1分钟理清楚C++类模板和模板类区别

    1.定义区别 类模板和模板类主要关注点是后一个单词. 类模板:主要描述的是模板,这个模板是类的模板.可以理解为一个通用的类,这个类中的数据成员,成员函数的形参类型以及成员函数的返回值类型不用具体的指定 ...

  4. Linux命令第三部分

    一.命令 1.mv命令 ·不更改文件路径 改名 ·更改文件路径 剪切 mv  [选项]  源文件或目录   目标文件或目录 2.which 查找命令.文件存放目录 搜索范围由环境变量PATH决定 3. ...

  5. JS传值与应用

    问题提出:在进行页面书写的时候,有时候需要进行动态页面拼接,在动态拼接的时候,涉及到函数的调用,函数的传值可能是HTML标签,或者含有json的标签,这样在传值时就有可能出现问题,由于"&q ...

  6. 一款极简的流媒体Web服务器(Streaming Media Web Server),提供视频音乐的在线播放功能

    一款极简的流媒体Web服务器(Streaming Media Web Server),提供视频音乐的在线播放功能 A extremely simple web server of streaming ...

  7. WPF 自定义附加事件

    我们都知道路由事件,而附加事件用的比较少. 但如果是通用的场景,类似附加属性,附加事件就很有必要的. 举个例子,输入设备有很多种,WPF中输入事件主要分为鼠标.触摸.触笔:WPF 屏幕点击的设备类型 ...

  8. js 禁用刷新快捷键

    // 上代码 /** * 按键监听 * Ctrl-17,F5-116,R-82 */ var oldKeyCode = -1; document.onkeydown = function (e) { ...

  9. python连接kafka-2.0

    import sysimport timeimport osimport jsonimport vertica_pythonimport loggingimport pykafkafrom pykaf ...

  10. 如何在现有的Vue项目中嵌入 Blazor项目?

    目前官方只提供了angular和react俩种示例,所以本教程将来讲解如何在Vue的现有项目中使用,上期已经做好了react的教材! 准备流程 Vue 项目创建流程 使用Vue创建一个Demo项目 全 ...