Host startup hook,是2.2中提供的一項新的功能,經過使用主機啓動鉤子,容許開發人員在不修改代碼的狀況下,在服務啓動以前注入代碼;經過使用鉤子,能夠對已部署好的服務在服務啓動期間自定義託管程序的行爲;經過使用鉤子,能夠對服務進行跟蹤或者遙測,也能夠在服務啓動前對託管環境進行健康檢查;還能夠經過鉤子動態加載程序集進行依賴注入等功能。html
鉤子的做用原理是經過設置環境變量 DOTNET_STARTUP_HOOKS 的值將鉤子程序掛載到託管程序之中,在託管程序啓動的時候,CoreCLR 將按照鉤子列表順序進行檢查,初始化後執行每一個鉤子程序,當鉤子列表中的鉤子程序被逐一執行完成後,託管程序將返回到程序主入口 Main 方法,進入一系列的啓動,鉤子程序能夠是任何 .Net Core 版本的類庫項目,在項目內必須包含類 StartupHook 這是固定命名,且 StartupHook 必須是一個沒有命名空間的內部類,包含默認的靜態方法 Initialize(),符合此規範便可做爲鉤子程序進行託管掛載web
Ron.HooksDemo 的代碼很是簡單,僅僅輸出一句話api
class Program { static void Main(string[] args) { Console.WriteLine("\n程序已啓動"); Console.ReadKey(); } }
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 異常app
2.2 運行程序,看看是否正確掛載了鉤子程序 Ron.Initasp.net
上圖紅色部分輸出信息表示鉤子程序掛載成功,藍色部分表示託管主機已啓動,能夠看到,託管主機啓動是在掛載鉤子以後運行的
必定要注意,鉤子是在託管程序的 Main 方法以前運行的.net
掛載多個鉤子的方法是設置環境變量 DOTNET_STARTUP_HOOKS 的值,多個鉤子按順序執行,其中 Windows 和 Unix 掛載多個鉤子的方式基本相同,這其中,有一點微小的區別3d
DOTNET_STARTUP_HOOKS = C:\Hooks_1.dll;C:\Hooks_2.dll
DOTNET_STARTUP_HOOKS =/data/Hooks_1.dll:/data/Hooks_2.dll
以上 DOTNET_STARTUP_HOOKS 變量的值包含兩個鉤子程序,其中 Windows 平臺的值爲使用分號(;)進行分隔,Unix 平臺使用冒號(:)進行分隔,這於傳統使用方式一致code
下面把兩個鉤子掛載到 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.Init 鉤子輸出信息,黃色部分是 Ron.License 輸出信息,藍色部分是託管主機 Ron.HooksDemo 輸出信息
能夠看到,鉤子上安裝掛載的順序執行的
咱們應該這麼理解,鉤子程序也是一個普通的應用程序集;因此一個普通的程序集能作到事情,鉤子也同樣能夠
public class UserService : IDisposable { public void Dispose() { Console.WriteLine("程序集:Ron.Service.dll"); Console.WriteLine("動態加載程序集,執行清理任務已完成\n\n"); Console.WriteLine("=========== Ron.Service.dll 結束 ==========="); } }
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 結束 ==========="); } }
從輸出結果看到,Ron.Service 程序集已被成功加載並調用,控制檯紅色輸出信息部分表示加載成功
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"
紅色輸出部分表示 Web Api 程序的 Main 方法在鉤子列表執行完成以後成功啓動,這表示在 .Net Core 中,掛載鉤子的方式是一致的,其行爲也相同
使用鉤子程序注意事項
- 鉤子程序不能依賴於託管主機的TPA列表以外的任何程序集,不然會拋出 FileNotFoundException 的異常
- 不要掛載過多的鉤子程序,這可能會出現兼容性問題,若是要使用多個鉤子,必須確保每一個鉤子程序的行爲都是獨立的,互不干擾的,若是必定要使用,建議修改託管主機的代碼,使用依賴注入的方式而不是鉤子
- StartupHook 類應該是 internal 類型的,若是是使用 public 進行修飾,仍是能夠正常加載鉤子程序
https://files.cnblogs.com/files/viter/Ron.HooksDemo.zip