目录

  • 前言
  • 什么是钩子
  • 使用钩子
  • 3. 挂载多个钩子
  • 4. 在钩子中加载额外的程序集
  • 5. 在 Asp.Net Web Api 项目中使用钩子
  • 结束语
  • 演示代码下载

前言

    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("程序已启动");            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},OSVersion:{1},version:{2},userName:{3},CurrentDirectory:{4}Core Count:{5}WorkSet:{6}Drives:{7}",            Environment.MachineName,            Environment.OSVersion,            Environment.Version,            Environment.UserName,            Environment.CurrentDirectory,            Environment.ProcessorCount,            Environment.WorkingSet,            string.Join(",", drives));        Console.WriteLine("正在获取网络配置.....");        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} Address:{1}", ip.AddressFamily, ip);        }        Console.WriteLine("正在上报启动信息.....");        Console.WriteLine("=========== Ron.Init.dll 结束 ===========");    }}

上面的代码即表示一个标准的钩子程序,在 Initialize() 内部,进行托管主机检查,获取网络配置等行为,最好,还打印一条上报到遥测服务器的信息,这里是模拟上报检查报告,最后输出结束信息代码非常检查,现在打开 Ron.HooksDemo 项目属性页进行钩子挂载

上图添加环境变量 DOTNET_STARTUP_HOOKS ,并设置其值为 C:甥敳獲AdministratorSourceReposRon.HooksDemoRon.InitbinDebugetcoreapp2.2Ron.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("程序集:Ron.License.dll");        Console.WriteLine("作者:Ron.liang");        Console.WriteLine("博客地址:https://www.cnblogs.com/viter/");        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("动态加载程序集,执行清理任务已完成");            Console.WriteLine("=========== Ron.Service.dll 结束 ===========");        }    }

4.2 在 Ron.License 的钩子方法中加载 Ron.Service 程序集,创建 IDisposable 的实现,并调用 Dispose() 方法

internal class StartupHook{    public static void Initialize()    {        Console.WriteLine("程序集:Ron.License.dll");        Console.WriteLine("作者:Ron.liang");        Console.WriteLine("博客地址:https://www.cnblogs.com/viter/");        string path = @"C:甥敳獲AdministratorSourceReposRon.HooksDemoRon.ServicebinDebugetcoreapp2.2Ron.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:甥敳獲AdministratorSourceReposRon.HooksDemoRon.InitbinDebugetcoreapp2.2Ron.Init.dll;C:甥敳獲AdministratorSourceReposRon.HooksDemoRon.LicensebinDebugetcoreapp2.2Ron.License.dll"

5.1 运行 Web Api 项目 Ron.HooksDemo.Web

红色输出部分表示 Web Api 程序的 Main 方法在钩子列表执行完成之后成功启动,这表示在 .Net Core 中,挂载钩子的方式是一致的,其行为也相同

结束语

使用钩子程序注意事项

钩子程序不能依赖于托管主机的TPA列表之外的任何程序集,否则会抛出 FileNotFoundException 的异常不要挂载过多的钩子程序,这可能会出现兼容性问题,如果要使用多个钩子,必须确保每个钩子程序的行为都是独立的,互不干扰的,如果一定要使用,建议修改托管主机的代码,使用依赖注入的方式而不是钩子StartupHook 类应该是 internal 类型的,如果是使用 public 进行修饰,还是可以正常加载钩子程序

c++ dll 类使用_在.Net Core 中使用钩子相关推荐

  1. .net使用httpclient获取http状态码_在 .NET Core 中结合 HttpClientFactory 使用 Polly(中篇)...

    译者:码农老王 作者:Polly 团队 原文:http://t.cn/EhZ90oq 声明:我翻译技术文章不是逐句翻译的,而是根据我自己的理解来表述的(包括标题).其中可能会去除一些不影响理解但本人实 ...

  2. netcore更新dll要停止_使 .NET Core 应用程序容器化

    在本教程中,你将了解如何使用 Docker 容器化 .NET Core 应用. 容器具有很多特性和优点,如具有不可变的基础结构.提供可移植的体系结构和实现可伸缩性. 此影像可用于为本地开发环境.私有云 ...

  3. python包里面的dll是什么_如何使用Python中的DLL文件?

    小编典典 为了易于使用,ctypes是必经之路. 以下ctypes示例来自我编写的实际代码(在Python 2.5中).到目前为止,这是我找到的最简单的方法来完成你的要求. import ctypes ...

  4. java栈 类 堆_详细介绍Java中的堆和栈

    栈与堆都是Java用来在RAM中寄存数据的中央.与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆. Java的堆是一个运转时数据区,类的对象从中分配空间.这些对象经过new.newar ...

  5. JAVA类思维_面向对象思维 Java中的类和对象及其应用

    一.面向过程与面向对象 面向过程: 从事务执行者的角度思考问题,我该干什么  重点在过程----事务流程 面向对象: 从事务的指挥者角度思考问题,我应该找谁干什么  重点在对象 面向对象的优点: 1. ...

  6. feign返回结果统一处理_在.net core中对接口返回属性名称做统一处理

    为了开发规范,有时需要统一响应属性名称,.netcore已为我们封装好了,我们直接用即可. 在StartUp类中ConfigureServices方法中,添加如下代码: public void Con ...

  7. java 可以继承不同包的类吗_深入理解JAVA中的跨包继承

    今天根据要求对集中访问控制符做了测试,在子类跨包继承的权限问题,发现有些矛盾. 代码说明:父类Father 在packageA中 子类Child01也在packageA中 子类Child02在pack ...

  8. java 类隔离_微服务架构中zuul的两种隔离机制实验

    ZuulException REJECTED_SEMAPHORE_EXECUTION 是一个最近在性能测试中经常遇到的异常.查询资料发现是因为zuul默认每个路由直接用信号量做隔离,并且默认值是100 ...

  9. csredis封装_在.NET Core中使用CSRedis

    CSRedis 为什么选择CSRedis ServiceStack.Redis 是商业版,免费版有限制: StackExchange.Redis 是免费版,但是内核在 .NETCore 运行有问题经常 ...

最新文章

  1. 如何在node.js中发出HTTP POST请求?
  2. iOS UI基础-11.0 UINavigationController
  3. 笔记-项目沟通管理-沟通基本原则
  4. 妙趣横生的算法--栈和队列
  5. 分享30个新鲜PSD网站模板免费下载
  6. conda虚拟环境中安装ipython
  7. halo多人正在连接服务器,在线人数过低 《光晕2》PC版多人服务器下月关闭
  8. cp 过程中目录突然挂了_怎么解决管材激光切割机切管过程中出现的过烧及挂渣...
  9. 经验与教训:测试员的偏向
  10. 6 获取当前模块_python常用模块的常用方法介绍
  11. VS2015 Cordova Ionic移动开发(一)
  12. Subversion for Windows 相关工具
  13. 一个人php建站_人人站CMS-简单安全的PHP开源CMS建站系统
  14. excel的lookup函数
  15. python数据处理可以做什么菜_python 文件处理
  16. linux新建目录自动777权限,什么是777权限?Linux及Windows下如何设置文件夹的权限为777?...
  17. 手工制作使用WinXShell的PE(不是直接生成) #1
  18. 外媒点赞,浪潮存储为何能入围全球最佳主存储供应商
  19. 计算机硬盘分区安全,Win10如何安全的给移动硬盘分区?win10给移动硬盘分区的方法...
  20. 复旦大学2020计算机考试大纲,复旦大学2020年硕士研究生招生考试自命题科目考试大纲-761卫生综合(一)大纲...

热门文章

  1. Delphi XE2获取汉字拼音首字母
  2. spanning-tree extend system-id
  3. stack overflow--技术问答网站
  4. python (3):wxPython打包app,报错
  5. C语言及程序设计进阶例程-17 认识链表
  6. 安装wps导致 application/kset 上传文件类型报错解决办法
  7. C#操作XmlDocument对象 报缺少根节点 一一道来
  8. IBM副总裁自述的数据中心简化经验
  9. 400. 第 N 位数字
  10. leetcode 1489. 找到最小生成树里的关键边和伪关键边(并查集)