.NET 6 整合 Autofac 依赖注入容器
前言
一行业务代码还没写,框架代码一大堆,不利于学习。
常看到java的学习资料或博客,标题一般为《SpringBoot 整合 XXX》,所以仿照着写了《.NET 6 整合 Autofac 依赖注入容器》这样一个标题。
以下是我自己的用法,可能不是最佳实践。
一. 引用包
NuGet搜索并安装:
Autofac
Autofac.Extensions.DependencyInjection
二. 配置代码
var builder = WebApplication.CreateBuilder(args);
...省略
// ASP.NET Core整合Autofac
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());//通过工厂替换,把Autofac整合进来
builder.Host.ConfigureContainer<ContainerBuilder>(containerBuilder =>
{
ServiceFactory.SetBuilder(containerBuilder);
ServiceFactory.RegisterAssembly(Assembly.GetExecutingAssembly()); //注册服务
});
var app = builder.Build();
ServiceFactory.SetContainer((app.Services as AutofacServiceProvider).LifetimeScope as IContainer);
Task.Run(async () => await ServiceFactory.StartAllService()); //启动服务,注意:服务启动完成之前,调用接口会异常
...省略
三. 服务的自动注册、启动、停止
IService接口
/// <summary>
/// 服务接口
/// </summary>
public interface IService
{
/// <summary>
/// 服务启动
/// </summary>
Task OnStart();
/// <summary>
/// 服务停止
/// </summary>
Task OnStop();
}
RegisterServiceAttribute特性
/// <summary>
/// 注册为服务
/// </summary>
public class RegisterServiceAttribute : Attribute
{
}
ServiceBase抽像类
[RegisterService]
public abstract class ServiceBase : IService
{
#region OnStart
public virtual Task OnStart()
{
return Task.CompletedTask;
}
#endregion
#region OnStop
public virtual Task OnStop()
{
return Task.CompletedTask;
}
#endregion
}
ServiceFactory服务工厂类
public class ServiceFactory
{
private static ContainerBuilder _builder;
private static IContainer _container;
private static bool _isRunning; //服务是否正在运行
public static void SetBuilder(ContainerBuilder builder)
{
_builder = builder;
}
public static void SetContainer(IContainer container)
{
_container = container;
}
/// <summary>
/// Autofac.ContainerBuilder
/// </summary>
public static ContainerBuilder Builder
{
get
{
return _builder;
}
}
/// <summary>
/// 获取服务
/// </summary>
/// <typeparam name="T">接口类型</typeparam>
public static T Get<T>()
{
if (_isRunning)
{
return _container.Resolve<T>();
}
else
{
throw new Exception("服务尚未启动完成");
}
}
/// <summary>
/// 获取服务
/// </summary>
/// <param name="type">接口类型</param>
public static object Get(Type type)
{
if (_isRunning)
{
return _container.Resolve(type);
}
else
{
throw new Exception("服务尚未启动完成");
}
}
#region 注册程序集
/// <summary>
/// 注册程序集
/// </summary>
/// <param name="serviceAssembly">服务程序集</param>
public static void RegisterAssembly(Assembly serviceAssembly)
{
Type[] typeArr = serviceAssembly.GetTypes();
foreach (Type type in typeArr)
{
if (type.GetCustomAttribute<RegisterServiceAttribute>() != null && !type.IsAbstract)
{
_builder.RegisterType(type).SingleInstance().AsImplementedInterfaces().AsSelf();
}
else
{
Type[] interfaceTypes = type.GetInterfaces();
foreach (Type interfaceType in interfaceTypes)
{
if (interfaceType.GetCustomAttribute<RegisterServiceAttribute>() != null && !type.IsAbstract)
{
_builder.RegisterType(type).SingleInstance().AsImplementedInterfaces().AsSelf();
break;
}
}
}
}
//_container = _builder.Build();
}
#endregion
#region 启动所有服务
/// <summary>
/// 启动所有服务
/// </summary>
public static async Task StartAllService()
{
Type iServiceInterfaceType = typeof(IService);
IEnumerable<Type> types = _container.ComponentRegistry.Registrations.Select(a => a.Activator.LimitType);
await Parallel.ForEachAsync(types, async (type, c) =>
{
if (iServiceInterfaceType.IsAssignableFrom(type))
{
object obj = _container.Resolve(type);
try
{
IService service = obj as IService;
await service.OnStart();
LogUtil.Info("服务 " + obj.GetType().FullName + " 已启动");
}
catch (Exception ex)
{
LogUtil.Error(ex, "服务 " + obj.GetType().FullName + " 启动失败");
}
}
});
_isRunning = true;
}
#endregion
#region 停止所有服务
/// <summary>
/// 停止所有服务
/// </summary>
public static async Task StopAllService()
{
Type iServiceInterfaceType = typeof(IService);
IEnumerable<Type> types = _container.ComponentRegistry.Registrations.Select(a => a.Activator.LimitType);
await Parallel.ForEachAsync(types, async (type, c) =>
{
if (iServiceInterfaceType.IsAssignableFrom(type))
{
object obj = _container.Resolve(type);
IService service = obj as IService;
try
{
await service.OnStop();
LogUtil.Info("服务 " + obj.GetType().FullName + " 已停止");
}
catch (Exception ex)
{
LogUtil.Error(ex, "服务 " + obj.GetType().FullName + " 停止失败");
}
}
});
_isRunning = false;
}
#endregion
}
ServiceFactory的简写类
/// <summary>
/// ServiceFactory的简写
/// </summary>
public class SF
{
/// <summary>
/// 获取服务
/// </summary>
/// <typeparam name="T">接口类型</typeparam>
public static T Get<T>()
{
return ServiceFactory.Get<T>();
}
/// <summary>
/// 获取服务
/// </summary>
/// <param name="type">接口类型</param>
public static object Get(Type type)
{
return ServiceFactory.Get(type);
}
}
编写服务类
服务类示例1
/// <summary>
/// 测试服务
/// </summary>
public class TestService : ServiceBase
{
public async Task<string> GetValue()
{
return await Task.FromResult("测试数据");
}
}
服务类示例2
重写了OnStart和OnStop以实现服务的启动和停止。
/// <summary>
/// 定时任务管理
/// </summary>
public class ScheduleJobs : ServiceBase
{
#region 变量
private IScheduler _scheduler;
#endregion
#region OnStart
public override async Task OnStart()
{
try
{
NameValueCollection options = new NameValueCollection();
string schedulerName = "DefaultQuartzScheduler";
options.Add("quartz.scheduler.instanceName", schedulerName);
StdSchedulerFactory schedulerFactory = new StdSchedulerFactory(options);
_scheduler = await schedulerFactory.GetScheduler(schedulerName);
if (_scheduler == null)
{
_scheduler = await schedulerFactory.GetScheduler();
}
await _scheduler.Start();
AddJobs(_scheduler);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
#endregion
#region OnStop
public override async Task OnStop()
{
await _scheduler.Shutdown();
}
#endregion
#region ScheduleJob
private async Task ScheduleJob<T>(IScheduler scheduler, string cronString) where T : IJob
{
IJobDetail jobDetail = JobBuilder.Create<T>().Build();
ITrigger trigger = TriggerBuilder.Create().WithCronSchedule(cronString).Build();
await scheduler.ScheduleJob(jobDetail, trigger);
}
#endregion
private async void AddJobs(IScheduler scheduler)
{
await ScheduleJob<TestJob>(scheduler, "0/30 * * * * ?");
}
}
构造注入示例
[ApiController]
[Route("[controller]")]
public class TestController : ControllerBase
{
private readonly TestService _testService;
public TestController(TestService testService)
{
_testService = testService;
}
...省略
}
也可以这样使用
var value = await SF.Get<TestService>().GetValue();
.NET 6 整合 Autofac 依赖注入容器的更多相关文章
- Autofac依赖注入容器
依赖注入容器-- Autofac https://github.com/danielpalme/IocPerformance Unity 更新频率高,微软的项目Grace 综合性能更高 目录: 一.简 ...
- 依赖注入容器Autofac的详解
Autofac和其他容器的不同之处是它和C#语言的结合非常紧密,在使用过程中对你的应用的侵入性几乎为零,更容易与第三方的组件集成,并且开源,Autofac的主要特性如下: 1,灵活的组件实例化:Aut ...
- Asp.Net Core 进阶(三)—— IServiceCollection依赖注入容器和使用Autofac替换它
Asp.Net Core 提供了默认的依赖注入容器 IServiceCollection,它是一个轻量级的依赖注入容器,所以功能不多,只是提供了基础的一些功能,要实现AOP就有点麻烦,因此在实际工作当 ...
- 从零开始,搭建博客系统MVC5+EF6搭建框架(2),测试添加数据、集成Autofac依赖注入
一.测试仓储层.业务层是否能实现对数据库表的操作 1.创建IsysUserInfoRepository接口来继承IBaseRepository父接口 namespace Wchl.WMBlog.IRe ...
- 【干货】利用MVC5+EF6搭建博客系统(二)测试添加数据、集成Autofac依赖注入
PS:如果图片模糊,鼠标右击复制图片网址,然后在浏览器中打开即可. 一.测试仓储层.业务层是否能实现对数据库表的操作 1.在52MVCBlog.IRepository程序集下创建IsysUserInf ...
- ASP.NETCore使用AutoFac依赖注入
原文:ASP.NETCore使用AutoFac依赖注入 实现代码 1.新建接口类:IRepository.cs,规范各个操作类的都有那些方法,方便管理. using System; using Sys ...
- ADO.NET .net core2.0添加json文件并转化成类注入控制器使用 简单了解 iTextSharp实现HTML to PDF ASP.NET MVC 中 Autofac依赖注入DI 控制反转IOC 了解一下 C# AutoMapper 了解一下
ADO.NET 一.ADO.NET概要 ADO.NET是.NET框架中的重要组件,主要用于完成C#应用程序访问数据库 二.ADO.NET的组成 ①System.Data → DataTable, ...
- Autofac依赖注入
简介 Autofac 是一款超赞的.NET IoC 容器 . 它管理类之间的依赖关系, 从而使 应用在规模及复杂性增长的情况下依然可以轻易地修改 .它的实现方式是将常规的.net类当做 组件 处理. ...
- Asp.net core自定义依赖注入容器,替换自带容器
依赖注入 在asp.net core程序中,众所周知,依赖注入基本上贯穿了整个项目,以通用的结构来讲解,控制器层(Controller层)依赖业务层(Service层),业务层依赖于仓储层(Repos ...
- WPF PRISM开发入门二(Unity依赖注入容器使用)
这篇博客将通过一个控制台程序简单了解下PRISM下Unity依赖注入容器的使用.我已经创建了一个例子,通过一个控制台程序进行加减乘除运算,项目当中将输入输出等都用接口封装后,结构如下: 当前代码可以点 ...
随机推荐
- MySQL笔记01: MySQL入门_1.3 MySQL启动停止与登录
1.3 MySQL启动停止与登录 1.3.1 MySQL启动与停止 MySQL数据库分为客户端和服务器端,只有服务器端服务开启以后,才可以通过客户端登录MySQL服务端. 首先,以管理员身份运行&qu ...
- [ABC261D] Flipping and Bonus
Problem Statement Takahashi will toss a coin $N$ times. He also has a counter, which initially shows ...
- Mybatis-Flex核心功能之@Table
1.能干啥? @Table 主要是用于给 Entity 实体类添加标识,用于描述 实体类 和 数据库表 的关系,以及对实体类进行的一些 功能辅助. 例如: 数据库有一张tb_member的会员表 这时 ...
- python tkinter使用(九)
python tkinter使用(九) 本文主要讲下scrolledText中图片的插入,以及常见的错误. 使用Image.open来打开图片 使用ImageTk.PhotoImage()方法将图片转 ...
- apache+mysql+php环境安装及配置
一.安装mysql 1.yum安装mysql # yum -y install mysql mysql-server 2.安装mariadb,用mariadb来启动数据库,systemctl star ...
- 2023-12-30:用go语言,给你一个下标从 0 开始的整数数组 nums ,它包含 n 个 互不相同 的正整数, 如果 nums 的一个排列满足以下条件,我们称它是一个特别的排列。 对于 0 <
2023-12-30:用go语言,给你一个下标从 0 开始的整数数组 nums ,它包含 n 个 互不相同 的正整数, 如果 nums 的一个排列满足以下条件,我们称它是一个特别的排列. 对于 0 & ...
- Config:Spring Cloud分布式配置组件
Config:Spring Cloud分布式配置组件 问题总结 Config? Config工作原理? Config 的特点? Config+Bus 实现配置的动态刷新? 问题答案 Config Co ...
- 前端系列:基于 Flex 弹性布局详解
目录 基本介绍 基本概念 父项常见属性 flex-direction justify-content flex-wrap align-items align-content flex-flow 子项常 ...
- Java面试必考:什么是字节码?采用字节码的好处?
Java面试必考:什么是字节码?采用字节码的好处? 于哥你好,最近在java面试中被问答到什么是字节码?采用字节码的好处是什么?瞬间懵了,如果你连这个都不知道,我保证你面试GG! 首先说下Java的优 ...
- 2023-06-04:你的音乐播放器里有 N 首不同的歌, 在旅途中,你的旅伴想要听 L 首歌(不一定不同,即,允许歌曲重复, 请你为她按如下规则创建一个播放列表, 每首歌至少播放一次, 一首歌只有在
2023-06-04:你的音乐播放器里有 N 首不同的歌, 在旅途中,你的旅伴想要听 L 首歌(不一定不同,即,允许歌曲重复, 请你为她按如下规则创建一个播放列表, 每首歌至少播放一次, 一首歌只有在 ...