.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依赖注入容器的使用.我已经创建了一个例子,通过一个控制台程序进行加减乘除运算,项目当中将输入输出等都用接口封装后,结构如下: 当前代码可以点 ...
随机推荐
- vivado生成Bitstream报错[Vivado 12-1345] Error(s) found during DRC. Bitgen not run(Vivado 2017.4)。
写了一个很简单的程序,2-4译码器. module decoder2to4( input in1, in0, output reg [3:0]out ); always @ (*) begin if ...
- 使用 sed 处理文本文件
前言 sed 是一款 GNU 流编辑器,可以按照指定的规则去处理文本文件或流,其强大的功能使用户在命令中快捷地修改文本文件成为可能. 它不会修改文件,除非使用shell重定向来保存结果.默认情况下,所 ...
- MySQL-管理员root@'locahost' 丢失,怎么处理?
版权声明:原创作品,谢绝转载!否则将追究法律责任. ----- 作者:kirin 跳过授权表 ----> 不开启验证功能(无密码登录) --skip-grant-tables 阻止所有tcp/i ...
- Vue02-小案例(购物车功能)
效果图 主要代码 index.html <!DOCTYPE html> <html lang="en"> <head> <meta cha ...
- maven 配置(cmd 黑窗口执行 mvn 时默认的 settings 文件和 idea maven 相关配置)
写在前面: 本文章用于记录博主平时遇到的问题,步骤略粗糙,目的在于记录一边后续博主自己查找,如果能帮助到其他人更好.文章中用到的链接均为自行引入,侵删,谢谢(2I2Rc*@JY8) 问题说明:在一次使 ...
- scroll-view和swiper的使用
源码: <template> <viex class="out"> <view class="b ...
- GoFrame Goland插件
前言 GoFrame 是一款模块化.高性能.企业级的 Go 基础开发框架.GoFrame 是一款通用性的基础开发框架,是 Golang 标准库的一个增强扩展级,包含通用核心的基础开发组件,优点是实战化 ...
- Scrapy集成selenium-案例-淘宝首页推荐商品获取
scrapy特性就是效率高,异步,如果非要集成selenium实际上意义不是特别大....因为selenium慢.... 案例:淘宝首页推荐商品的标题获取 爬虫类 toabao.py import s ...
- Spring源码学习之Web数据绑定器WebDataBinder
WebDataBinder 1.描述 特殊的数据绑定器用于从web请求参数到JavaBean对象的数据绑定.专为web环境,但不依赖于Servlet API;作为更具体的DataBinder变体的基类 ...
- ASR项目实战-交付过程中遇到的疑似内存泄漏问题
基于Kaldi实现语音识别时,需要引入一款名为OpenFST的开源软件,本文中提到的内存问题,即和这款软件相关. 考虑到过程比较曲折,内容相对比较长,因此先说结论. 在做长时间的语音识别时,集成了Ka ...