c++ dll 类使用_在.Net Core 中使用钩子
目錄
- 前言
- 什么是鉤子
- 使用鉤子
- 3. 掛載多個(gè)鉤子
- 4. 在鉤子中加載額外的程序集
- 5. 在 Asp.Net Web Api 項(xiàng)目中使用鉤子
- 結(jié)束語(yǔ)
- 演示代碼下載
前言
????Host startup hook,是2.2中提供的一項(xiàng)新的功能,通過(guò)使用主機(jī)啟動(dòng)鉤子,允許開(kāi)發(fā)人員在不修改代碼的情況下,在服務(wù)啟動(dòng)之前注入代碼;通過(guò)使用鉤子,可以對(duì)已部署好的服務(wù)在服務(wù)啟動(dòng)期間自定義托管程序的行為;通過(guò)使用鉤子,可以對(duì)服務(wù)進(jìn)行跟蹤或者遙測(cè),也可以在服務(wù)啟動(dòng)前對(duì)托管環(huán)境進(jìn)行健康檢查;還可以通過(guò)鉤子動(dòng)態(tài)加載程序集進(jìn)行依賴(lài)注入等功能。
什么是鉤子
鉤子的作用原理是通過(guò)設(shè)置環(huán)境變量 DOTNET_STARTUP_HOOKS 的值將鉤子程序掛載到托管程序之中,在托管程序啟動(dòng)的時(shí)候,CoreCLR 將按照鉤子列表順序進(jìn)行檢查,初始化后執(zhí)行每個(gè)鉤子程序,當(dāng)鉤子列表中的鉤子程序被逐一執(zhí)行完成后,托管程序?qū)⒎祷氐匠绦蛑魅肟?Main 方法,進(jìn)入一系列的啟動(dòng),鉤子程序可以是任何 .Net Core 版本的類(lèi)庫(kù)項(xiàng)目,在項(xiàng)目?jī)?nèi)必須包含類(lèi) StartupHook 這是固定命名,且 StartupHook 必須是一個(gè)沒(méi)有命名空間的內(nèi)部類(lèi),包含默認(rèn)的靜態(tài)方法 Initialize(),符合此規(guī)范即可作為鉤子程序進(jìn)行托管掛載
使用鉤子
1.首先創(chuàng)建一個(gè)控制臺(tái)項(xiàng)目 Ron.HooksDemo ,作為托管主機(jī),用于掛載鉤子程序 Ron.Init
Ron.HooksDemo 的代碼非常簡(jiǎn)單,僅僅輸出一句話(huà)
class Program { static void Main(string[] args) { Console.WriteLine("程序已啟動(dòng)"); Console.ReadKey(); } }2. 創(chuàng)建鉤子程序,Ron.Init
2.1 按照鉤子程序的規(guī)范,創(chuàng)建一個(gè)無(wú)命名空間的內(nèi)部類(lèi) StartupHook ,且包含默認(rèn)靜態(tài)方法 Initialize()
internal class StartupHook{ public static void Initialize() { Console.WriteLine("程序集:Ron.Init.dll"); Console.WriteLine("正在獲取服務(wù)器信息....."); 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("正在獲取網(wǎng)絡(luò)配置....."); 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("正在上報(bào)啟動(dòng)信息....."); Console.WriteLine("=========== Ron.Init.dll 結(jié)束 ==========="); }}上面的代碼即表示一個(gè)標(biāo)準(zhǔn)的鉤子程序,在 Initialize() 內(nèi)部,進(jìn)行托管主機(jī)檢查,獲取網(wǎng)絡(luò)配置等行為,最好,還打印一條上報(bào)到遙測(cè)服務(wù)器的信息,這里是模擬上報(bào)檢查報(bào)告,最后輸出結(jié)束信息代碼非常檢查,現(xiàn)在打開(kāi) Ron.HooksDemo 項(xiàng)目屬性頁(yè)進(jìn)行鉤子掛載
上圖添加環(huán)境變量 DOTNET_STARTUP_HOOKS ,并設(shè)置其值為 C:甥敳獲AdministratorSourceReposRon.HooksDemoRon.InitbinDebugetcoreapp2.2Ron.Init.dll,這是本次示例的鉤子程序絕對(duì)路徑注意:該環(huán)境變量的值不支持相對(duì)路徑,如果嘗試使用相對(duì)路徑,托管主機(jī)將拋出 ArgumentException 異常
2.2 運(yùn)行程序,看看是否正確掛載了鉤子程序 Ron.Init
上圖紅色部分輸出信息表示鉤子程序掛載成功,藍(lán)色部分表示托管主機(jī)已啟動(dòng),可以看到,托管主機(jī)啟動(dòng)是在掛載鉤子之后運(yùn)行的一定要注意,鉤子是在托管程序的 Main 方法之前運(yùn)行的
3. 掛載多個(gè)鉤子
3.1 一個(gè)托管程序可以?huà)燧d多個(gè)鉤子
掛載多個(gè)鉤子的方法是設(shè)置環(huán)境變量 DOTNET_STARTUP_HOOKS 的值,多個(gè)鉤子按順序執(zhí)行,其中 Windows 和 Unix 掛載多個(gè)鉤子的方式基本相同,這其中,有一點(diǎn)微小的區(qū)別
- Windows 平臺(tái)掛載方式
- Unix 平臺(tái)掛載方式
以上 DOTNET_STARTUP_HOOKS 變量的值包含兩個(gè)鉤子程序,其中 Windows 平臺(tái)的值為使用分號(hào)(;)進(jìn)行分隔,Unix 平臺(tái)使用冒號(hào)(:)進(jìn)行分隔,這于傳統(tǒng)使用方式一致
3.2 運(yùn)行掛載了多個(gè)鉤子的托管程序
- 下面把兩個(gè)鉤子掛載到 Ron.HooksDemo 項(xiàng)目后,他們分別是:Ron.Init 和 Ron.License
Ron.Init 鉤子輸出的是檢查服務(wù)器信息,這個(gè)信息在之前已經(jīng)演示,這里不再重復(fù),下面看 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 結(jié)束 ==========="); }- 鉤子程序的 Ron.License 代碼也非常簡(jiǎn)單,結(jié)構(gòu)和 Ron.Init 鉤子程序一致,只是簡(jiǎn)單的輸出版權(quán)信息
3.3 運(yùn)行 Ron.HooksDemo 程序,看下圖輸出結(jié)果
紅色部分是 Ron.Init 鉤子輸出信息,黃色部分是 Ron.License 輸出信息,藍(lán)色部分是托管主機(jī) Ron.HooksDemo 輸出信息可以看到,鉤子上安裝掛載的順序執(zhí)行的
4. 在鉤子中加載額外的程序集
我們應(yīng)該這么理解,鉤子程序也是一個(gè)普通的應(yīng)用程序集;所以一個(gè)普通的程序集能做到事情,鉤子也一樣可以
4.1 在 Ron.License 加載一個(gè)程序集 Ron.Service,Ron.Service 中定義了一個(gè)類(lèi) UserService,繼承自并實(shí)現(xiàn) IDisposable 接口
public class UserService : IDisposable { public void Dispose() { Console.WriteLine("程序集:Ron.Service.dll"); Console.WriteLine("動(dòng)態(tài)加載程序集,執(zhí)行清理任務(wù)已完成"); Console.WriteLine("=========== Ron.Service.dll 結(jié)束 ==========="); } }4.2 在 Ron.License 的鉤子方法中加載 Ron.Service 程序集,創(chuàng)建 IDisposable 的實(shí)現(xiàn),并調(diào)用 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 結(jié)束 ==========="); }}4.3 運(yùn)行程序 Ron.HooksDemo
從輸出結(jié)果看到,Ron.Service 程序集已被成功加載并調(diào)用,控制臺(tái)紅色輸出信息部分表示加載成功
5. 在 Asp.Net Web Api 項(xiàng)目中使用鉤子
Web Api 項(xiàng)目掛載鉤子的方式和控制臺(tái)方式相同,首先我們還是創(chuàng)建一個(gè) Web Api 項(xiàng)目 Ron.HooksDemo.Web接著掛載鉤子
"DOTNET_STARTUP_HOOKS": "C:甥敳獲AdministratorSourceReposRon.HooksDemoRon.InitbinDebugetcoreapp2.2Ron.Init.dll;C:甥敳獲AdministratorSourceReposRon.HooksDemoRon.LicensebinDebugetcoreapp2.2Ron.License.dll"5.1 運(yùn)行 Web Api 項(xiàng)目 Ron.HooksDemo.Web
紅色輸出部分表示 Web Api 程序的 Main 方法在鉤子列表執(zhí)行完成之后成功啟動(dòng),這表示在 .Net Core 中,掛載鉤子的方式是一致的,其行為也相同
結(jié)束語(yǔ)
使用鉤子程序注意事項(xiàng)
鉤子程序不能依賴(lài)于托管主機(jī)的TPA列表之外的任何程序集,否則會(huì)拋出 FileNotFoundException 的異常不要掛載過(guò)多的鉤子程序,這可能會(huì)出現(xiàn)兼容性問(wèn)題,如果要使用多個(gè)鉤子,必須確保每個(gè)鉤子程序的行為都是獨(dú)立的,互不干擾的,如果一定要使用,建議修改托管主機(jī)的代碼,使用依賴(lài)注入的方式而不是鉤子StartupHook 類(lèi)應(yīng)該是 internal 類(lèi)型的,如果是使用 public 進(jìn)行修飾,還是可以正常加載鉤子程序
總結(jié)
以上是生活随笔為你收集整理的c++ dll 类使用_在.Net Core 中使用钩子的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【iqiqiya专版】超级网易云音乐V1
- 下一篇: [USACO13JAN] Cow Lin