Asp.Net Core 轻松学-在.Net Core 中使用钩子
前言
Host startup hook,是2.2中提供的一项新的功能,通过使用主机启动钩子,允许开发人员在不修改代码的情况下,在服务启动之前注入代码;通过使用钩子,可以对已部署好的服务在服务启动期间自定义托管程序的行为;通过使用钩子,可以对服务进行跟踪或者遥测,也可以在服务启动前对托管环境进行健康检查;还可以通过钩子动态加载程序集进行依赖注入等功能。
什么是钩子
钩子的作用原理是通过设置环境变量 DOTNET_STARTUP_HOOKS 的值将钩子程序挂载到托管程序之中,在托管程序启动的时候,CoreCLR 将按照钩子列表顺序进行检查,初始化后执行每个钩子程序,当钩子列表中的钩子程序被逐一执行完成后,托管程序将返回到程序主入口 Main 方法,进入一系列的启动,钩子程序可以是任何 .Net Core 版本的类库项目,在项目内必须包含类 StartupHook 这是固定命名,且 StartupHook 必须是一个没有命名空间的内部类,包含默认的静态方法 Initialize(),符合此规范即可作为钩子程序进行托管挂载
使用钩子
1.首先创建一个控制台项目 Ron.HooksDemo ,作为托管主机,用于挂载钩子程序 Ron.Init
Ron.HooksDemo 的代码非常简单,仅仅输出一句话
class Program
{
static void Main(string[] args)
{
Console.WriteLine("\n程序已启动");
Console.ReadKey();
}
}
2. 创建钩子程序,Ron.Init
2.1 按照钩子程序的规范,创建一个无命名空间的内部类 StartupHook ,且包含默认静态方法 Initialize()
internal class StartupHook
{
public static void Initialize()
{
Console.WriteLine("程序集:Ron.Init.dll");
Console.WriteLine("正在获取服务器信息.....");
string[] drives = Environment.GetLogicalDrives();
Console.WriteLine("machineName:{0},\nOSVersion:{1},\nversion:{2},\nuserName:{3},\nCurrentDirectory:{4}\nCore Count:{5}\nWorkSet:{6}\nDrives:{7}",
Environment.MachineName,
Environment.OSVersion,
Environment.Version,
Environment.UserName,
Environment.CurrentDirectory,
Environment.ProcessorCount,
Environment.WorkingSet,
string.Join(",", drives));
Console.WriteLine("\n\n正在获取网络配置.....");
var hostName = Dns.GetHostName();
Console.WriteLine("HostName:{0}", hostName);
var addresses = Dns.GetHostAddresses(hostName);
foreach (var item in addresses)
{
IPAddress ip = item.MapToIPv4();
Console.WriteLine("AddressFamily:{0} \tAddress:{1}", ip.AddressFamily, ip);
}
Console.WriteLine("\n\n正在上报启动信息.....");
Console.WriteLine("=========== Ron.Init.dll 结束 ===========");
}
}
上面的代码即表示一个标准的钩子程序,在 Initialize() 内部,进行托管主机检查,获取网络配置等行为,最好,还打印一条上报到遥测服务器的信息,这里是模拟上报检查报告,最后输出结束信息
代码非常检查,现在打开 Ron.HooksDemo 项目属性页进行钩子挂载
上图添加环境变量 DOTNET_STARTUP_HOOKS ,并设置其值为 C:\Users\Administrator\Source\Repos\Ron.HooksDemo\Ron.Init\bin\Debug\netcoreapp2.2\Ron.Init.dll,这是本次示例的钩子程序绝对路径
注意:该环境变量的值不支持相对路径,如果尝试使用相对路径,托管主机将抛出 ArgumentException 异常
2.2 运行程序,看看是否正确挂载了钩子程序 Ron.Init
上图红色部分输出信息表示钩子程序挂载成功,蓝色部分表示托管主机已启动,可以看到,托管主机启动是在挂载钩子之后运行的
一定要注意,钩子是在托管程序的 Main 方法之前运行的
3. 挂载多个钩子
3.1 一个托管程序可以挂载多个钩子
挂载多个钩子的方法是设置环境变量 DOTNET_STARTUP_HOOKS 的值,多个钩子按顺序执行,其中 Windows 和 Unix 挂载多个钩子的方式基本相同,这其中,有一点微小的区别
- Windows 平台挂载方式
DOTNET_STARTUP_HOOKS = C:\Hooks_1.dll;C:\Hooks_2.dll
- Unix 平台挂载方式
DOTNET_STARTUP_HOOKS =/data/Hooks_1.dll:/data/Hooks_2.dll
以上 DOTNET_STARTUP_HOOKS 变量的值包含两个钩子程序,其中 Windows 平台的值为使用分号(;)进行分隔,Unix 平台使用冒号(:)进行分隔,这于传统使用方式一致
3.2 运行挂载了多个钩子的托管程序
- 下面把两个钩子挂载到 Ron.HooksDemo 项目后,他们分别是:Ron.Init 和 Ron.License
Ron.Init 钩子输出的是检查服务器信息,这个信息在之前已经演示,这里不再重复,下面看 Ron.License 代码
public static void Initialize()
{
Console.WriteLine("\n\n程序集:Ron.License.dll");
Console.WriteLine("作者:Ron.liang");
Console.WriteLine("博客地址:https://www.cnblogs.com/viter/\n\n");
Console.WriteLine("=========== Ron.License.dll 结束 ===========");
}
- 钩子程序的 Ron.License 代码也非常简单,结构和 Ron.Init 钩子程序一致,只是简单的输出版权信息
3.3 运行 Ron.HooksDemo 程序,看下图输出结果
红色部分是 Ron.Init 钩子输出信息,黄色部分是 Ron.License 输出信息,蓝色部分是托管主机 Ron.HooksDemo 输出信息
可以看到,钩子上安装挂载的顺序执行的
4. 在钩子中加载额外的程序集
我们应该这么理解,钩子程序也是一个普通的应用程序集;所以一个普通的程序集能做到事情,钩子也一样可以
4.1 在 Ron.License 加载一个程序集 Ron.Service,Ron.Service 中定义了一个类 UserService,继承自并实现 IDisposable 接口
public class UserService : IDisposable
{
public void Dispose()
{
Console.WriteLine("程序集:Ron.Service.dll");
Console.WriteLine("动态加载程序集,执行清理任务已完成\n\n");
Console.WriteLine("=========== Ron.Service.dll 结束 ===========");
}
}
4.2 在 Ron.License 的钩子方法中加载 Ron.Service 程序集,创建 IDisposable 的实现,并调用 Dispose() 方法
internal class StartupHook
{
public static void Initialize()
{
Console.WriteLine("\n\n程序集:Ron.License.dll");
Console.WriteLine("作者:Ron.liang");
Console.WriteLine("博客地址:https://www.cnblogs.com/viter/\n\n");
string path = @"C:\Users\Administrator\Source\Repos\Ron.HooksDemo\Ron.Service\bin\Debug\netcoreapp2.2\Ron.Service.dll";
var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(path);
dynamic obj = assembly.CreateInstance("Ron.Service.UserService");
obj.Dispose();
Console.WriteLine("=========== Ron.License.dll 结束 ===========");
}
}
4.3 运行程序 Ron.HooksDemo
从输出结果看到,Ron.Service 程序集已被成功加载并调用,控制台红色输出信息部分表示加载成功
5. 在 Asp.Net Web Api 项目中使用钩子
Web Api 项目挂载钩子的方式和控制台方式相同,首先我们还是创建一个 Web Api 项目 Ron.HooksDemo.Web
接着挂载钩子
"DOTNET_STARTUP_HOOKS": "C:\\Users\\Administrator\\Source\\Repos\\Ron.HooksDemo\\Ron.Init\\bin\\Debug\\netcoreapp2.2\\Ron.Init.dll;C:\\Users\\Administrator\\Source\\Repos\\Ron.HooksDemo\\Ron.License\\bin\\Debug\\netcoreapp2.2\\Ron.License.dll"
5.1 运行 Web Api 项目 Ron.HooksDemo.Web
红色输出部分表示 Web Api 程序的 Main 方法在钩子列表执行完成之后成功启动,这表示在 .Net Core 中,挂载钩子的方式是一致的,其行为也相同
结束语
使用钩子程序注意事项
- 钩子程序不能依赖于托管主机的TPA列表之外的任何程序集,否则会抛出 FileNotFoundException 的异常
- 不要挂载过多的钩子程序,这可能会出现兼容性问题,如果要使用多个钩子,必须确保每个钩子程序的行为都是独立的,互不干扰的,如果一定要使用,建议修改托管主机的代码,使用依赖注入的方式而不是钩子
- StartupHook 类应该是 internal 类型的,如果是使用 public 进行修饰,还是可以正常加载钩子程序
演示代码下载
https://github.com/lianggx/EasyAspNetCoreDemo/tree/master/Ron.HooksDemo
Asp.Net Core 轻松学-在.Net Core 中使用钩子的更多相关文章
- Asp.Net Core 轻松学-在.Net Core 使用缓存和配置依赖策略
前言 几乎在所有的应用程序中,缓存都是一个永恒的话题,恰当的使用缓存可以有效提高应用程序的性能:在某些业务场景下,使用缓存依赖会有很好的体验:在 Asp.Net Core 中,支持了多种缓存组 ...
- Asp.Net Core 轻松学-使用MariaDB/MySql/PostgreSQL和支持多个上下文对象
前言 在上一篇文章中(Asp.Net Core 轻松学-10分钟使用EFCore连接MSSQL数据库)[https://www.cnblogs.com/viter/p/10243577.html],介 ...
- Asp.Net Core 轻松学-多线程之Task(补充)
前言 在上一章 Asp.Net Core 轻松学-多线程之Task快速上手 文章中,介绍了使用Task的各种常用场景,但是感觉有部分内容还没有完善,在这里补充一下. 1. 任务的等待 在使用 ...
- Asp.Net Core 轻松学-利用文件监视进行快速测试开发
前言 在进行 Asp.Net Core 应用程序开发过程中,通常的做法是先把业务代码开发完成,然后建立单元测试,最后进入本地系统集成测试:在这个过程中,程序员的大部分时间几乎都花费在开发.运行 ...
- 如何从40亿整数中找到不存在的一个 webservice Asp.Net Core 轻松学-10分钟使用EFCore连接MSSQL数据库 WPF实战案例-打印 RabbitMQ与.net core(五) topic类型 与 headers类型 的Exchange
如何从40亿整数中找到不存在的一个 前言 给定一个最多包含40亿个随机排列的32位的顺序整数的顺序文件,找出一个不在文件中的32位整数.(在文件中至少确实一个这样的数-为什么?).在具有足够内存的情况 ...
- WebAPI调用笔记 ASP.NET CORE 学习之自定义异常处理 MySQL数据库查询优化建议 .NET操作XML文件之泛型集合的序列化与反序列化 Asp.Net Core 轻松学-多线程之Task快速上手 Asp.Net Core 轻松学-多线程之Task(补充)
WebAPI调用笔记 前言 即时通信项目中初次调用OA接口遇到了一些问题,因为本人从业后几乎一直做CS端项目,一个简单的WebAPI调用居然浪费了不少时间,特此记录. 接口描述 首先说明一下,基于 ...
- C# 中一些类关系的判定方法 C#中关于增强类功能的几种方式 Asp.Net Core 轻松学-多线程之取消令牌
1. IsAssignableFrom实例方法 判断一个类或者接口是否继承自另一个指定的类或者接口. public interface IAnimal { } public interface ID ...
- Asp.Net Core 轻松学-一行代码搞定文件上传 JSONHelper
Asp.Net Core 轻松学-一行代码搞定文件上传 前言 在 Web 应用程序开发过程中,总是无法避免涉及到文件上传,这次我们来聊一聊怎么去实现一个简单方便可复用文件上传功能:通过创建 ...
- Asp.Net Core 轻松学系列-1阅读指引目录
https://www.cnblogs.com/viter/p/10474091.html 目录 前言 1. 从安装到配置 2. 业务实现 3. 日志 4. 测试 5. 缓存使用 6.网络和通讯 7. ...
随机推荐
- BZOJ_2795_[Poi2012]A Horrible Poem_hash+暴力
Description 给出一个由小写英文字母组成的字符串S,再给出q个询问,要求回答S某个子串的最短循环节. 如果字符串B是字符串A的循环节,那么A可以由B重复若干次得到. Input 第一行一个正 ...
- Hadoop权限管理
1.Hadoop权限管理包括以下几个模块: (1) 用户分组管理.用于按组为单位组织管理,某个用户只能向固定分组中提交作业,只能使用固定分组中配置的资源:同时可以限制每个用户提交的作业数,使用的资源量 ...
- [转]现代Linux系统上的栈溢出攻击
1. 基本内容 这个教程试着向读者展示最基本的栈溢出攻击和现代Linux发行版中针对这种攻击的防御机制.为此我选择了最新版本的Ubuntu系统(12.10),因为它默认集成了几个安全防御机制,而且它也 ...
- 信息论随笔3: 交叉熵与TF-IDF模型
接上文:信息论随笔2: 交叉熵.相对熵,及上上文:信息论随笔 在读<数学之美>的时候,相关性那一节对TF-IDF模型有这样一句描述:"其实 IDF 的概念就是一个特定条件下.关键 ...
- jquery简易版xwPop.js弹出消息对话框插件
xwPop.js弹出消息对话框插件是一款含有多种情景模式的原生模态消息对话框代码,可用于替代浏览器默认的alert弹出对话框,它提供各种参数和方法,功能非常强大.目前已经在项目中有应用到xwpop开发 ...
- 排序算法——(2)Python实现十大常用排序算法
上期为大家讲解了排序算法常见的几个概念: 相关性:排序时是否需要比较元素 稳定性:相同元素排序后是否可能打乱 时间空间复杂度:随着元素增加时间和空间随之变化的函数 如果有遗忘的同学可以看排序算法——( ...
- .NET Core IdentityServer4实战 第一章-入门与API添加客户端凭据
内容:本文带大家使用IdentityServer4进行对API授权保护的基本策略 作者:zara(张子浩) 欢迎分享,但需在文章鲜明处留下原文地址. 本文将要讲述如何使用IdentityServer4 ...
- Celery异步调度框架(二)与Django结合使用
配置Celery与Django结合 需要安装的插件 # 用于在Django中执行任务 pip install django-celery-beat # 这个是把任务执行结果保存到django-orm中 ...
- .NETCore 千星项目模块化开发框架 SimplCommerce 详解
SimplCommerce 是 github 上过千星的.netcore 商城示例项目,本文详解他的模块化框架现实思路,其业务(如产品.订单)不作介绍.因作者文笔水平很差,它又很值得学习和推荐,就算不 ...
- .net相关知识
1.简述 private. protected. public. internal 修饰符的访问权限. private : 私有成员, 在类的内部才可以访问. protected : 保护成员,该 ...