前言

一行业务代码还没写,框架代码一大堆,不利于学习。

常看到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 依赖注入容器的更多相关文章

  1. Autofac依赖注入容器

    依赖注入容器-- Autofac https://github.com/danielpalme/IocPerformance Unity 更新频率高,微软的项目Grace 综合性能更高 目录: 一.简 ...

  2. 依赖注入容器Autofac的详解

    Autofac和其他容器的不同之处是它和C#语言的结合非常紧密,在使用过程中对你的应用的侵入性几乎为零,更容易与第三方的组件集成,并且开源,Autofac的主要特性如下: 1,灵活的组件实例化:Aut ...

  3. Asp.Net Core 进阶(三)—— IServiceCollection依赖注入容器和使用Autofac替换它

    Asp.Net Core 提供了默认的依赖注入容器 IServiceCollection,它是一个轻量级的依赖注入容器,所以功能不多,只是提供了基础的一些功能,要实现AOP就有点麻烦,因此在实际工作当 ...

  4. 从零开始,搭建博客系统MVC5+EF6搭建框架(2),测试添加数据、集成Autofac依赖注入

    一.测试仓储层.业务层是否能实现对数据库表的操作 1.创建IsysUserInfoRepository接口来继承IBaseRepository父接口 namespace Wchl.WMBlog.IRe ...

  5. 【干货】利用MVC5+EF6搭建博客系统(二)测试添加数据、集成Autofac依赖注入

    PS:如果图片模糊,鼠标右击复制图片网址,然后在浏览器中打开即可. 一.测试仓储层.业务层是否能实现对数据库表的操作 1.在52MVCBlog.IRepository程序集下创建IsysUserInf ...

  6. ASP.NETCore使用AutoFac依赖注入

    原文:ASP.NETCore使用AutoFac依赖注入 实现代码 1.新建接口类:IRepository.cs,规范各个操作类的都有那些方法,方便管理. using System; using Sys ...

  7. 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, ...

  8. Autofac依赖注入

    简介 Autofac 是一款超赞的.NET IoC 容器 . 它管理类之间的依赖关系, 从而使 应用在规模及复杂性增长的情况下依然可以轻易地修改 .它的实现方式是将常规的.net类当做 组件 处理. ...

  9. Asp.net core自定义依赖注入容器,替换自带容器

    依赖注入 在asp.net core程序中,众所周知,依赖注入基本上贯穿了整个项目,以通用的结构来讲解,控制器层(Controller层)依赖业务层(Service层),业务层依赖于仓储层(Repos ...

  10. WPF PRISM开发入门二(Unity依赖注入容器使用)

    这篇博客将通过一个控制台程序简单了解下PRISM下Unity依赖注入容器的使用.我已经创建了一个例子,通过一个控制台程序进行加减乘除运算,项目当中将输入输出等都用接口封装后,结构如下: 当前代码可以点 ...

随机推荐

  1. MySQL笔记01: MySQL入门_1.3 MySQL启动停止与登录

    1.3 MySQL启动停止与登录 1.3.1 MySQL启动与停止 MySQL数据库分为客户端和服务器端,只有服务器端服务开启以后,才可以通过客户端登录MySQL服务端. 首先,以管理员身份运行&qu ...

  2. [ABC261D] Flipping and Bonus

    Problem Statement Takahashi will toss a coin $N$ times. He also has a counter, which initially shows ...

  3. Mybatis-Flex核心功能之@Table

    1.能干啥? @Table 主要是用于给 Entity 实体类添加标识,用于描述 实体类 和 数据库表 的关系,以及对实体类进行的一些 功能辅助. 例如: 数据库有一张tb_member的会员表 这时 ...

  4. python tkinter使用(九)

    python tkinter使用(九) 本文主要讲下scrolledText中图片的插入,以及常见的错误. 使用Image.open来打开图片 使用ImageTk.PhotoImage()方法将图片转 ...

  5. apache+mysql+php环境安装及配置

    一.安装mysql 1.yum安装mysql # yum -y install mysql mysql-server 2.安装mariadb,用mariadb来启动数据库,systemctl star ...

  6. 2023-12-30:用go语言,给你一个下标从 0 开始的整数数组 nums ,它包含 n 个 互不相同 的正整数, 如果 nums 的一个排列满足以下条件,我们称它是一个特别的排列。 对于 0 <

    2023-12-30:用go语言,给你一个下标从 0 开始的整数数组 nums ,它包含 n 个 互不相同 的正整数, 如果 nums 的一个排列满足以下条件,我们称它是一个特别的排列. 对于 0 & ...

  7. Config:Spring Cloud分布式配置组件

    Config:Spring Cloud分布式配置组件 问题总结 Config? Config工作原理? Config 的特点? Config+Bus 实现配置的动态刷新? 问题答案 Config Co ...

  8. 前端系列:基于 Flex 弹性布局详解

    目录 基本介绍 基本概念 父项常见属性 flex-direction justify-content flex-wrap align-items align-content flex-flow 子项常 ...

  9. Java面试必考:什么是字节码?采用字节码的好处?

    Java面试必考:什么是字节码?采用字节码的好处? 于哥你好,最近在java面试中被问答到什么是字节码?采用字节码的好处是什么?瞬间懵了,如果你连这个都不知道,我保证你面试GG! 首先说下Java的优 ...

  10. 2023-06-04:你的音乐播放器里有 N 首不同的歌, 在旅途中,你的旅伴想要听 L 首歌(不一定不同,即,允许歌曲重复, 请你为她按如下规则创建一个播放列表, 每首歌至少播放一次, 一首歌只有在

    2023-06-04:你的音乐播放器里有 N 首不同的歌, 在旅途中,你的旅伴想要听 L 首歌(不一定不同,即,允许歌曲重复, 请你为她按如下规则创建一个播放列表, 每首歌至少播放一次, 一首歌只有在 ...