如何在Windows服务安装器中动态设置InstrumentedAttribute命名空间参数?
嘿,我来帮你搞定这个动态设置WMI Instrumented命名空间的问题!
首先要明确:程序集级的InstrumentedAttribute是编译时就固定下来的,没办法在安装阶段或者运行时直接修改它的参数。所以咱们得换个思路,绕开静态属性的限制,手动控制WMI命名空间的注册和服务启动时的初始化。
下面是具体的实现步骤,结合你的ProjectInstaller代码来调整:
1. 移除静态程序集属性
先把代码顶部的<Assembly: Instrumented("Root/EnRoute/Interfaces/Spill")>这一行删掉,我们不再依赖这个静态配置。
2. 修改ProjectInstaller:确保WMI命名空间存在
在你的Install方法中,添加代码来动态创建WMI命名空间(从配置文件读取命名空间值)。这样安装服务时,会先确保目标命名空间存在:
Imports System.Configuration Imports System.IO Imports System.Management Public Overrides Sub Install(stateSaver As IDictionary) MyBase.Install(stateSaver) ' 读取配置文件中的WMI命名空间(从传入的configName参数加载对应配置) Dim configNamespace As String = String.Empty If Context.Parameters.ContainsKey("configName") Then ' 构建配置文件路径 Dim configPath As String = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{Context.Parameters.Item("configName")}.config") Dim configMap As New ExeConfigurationFileMap() With {.ExeConfigFilename = configPath} Dim configSettings As Configuration = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None) ' 读取配置项,没有的话用默认值 configNamespace = configSettings.AppSettings.Settings("WmiNamespace")?.Value ?? "Root/EnRoute/Interfaces/Spill" End If ' 逐级创建WMI命名空间(避免直接创建多级失败) If Not String.IsNullOrEmpty(configNamespace) Then Dim namespaceParts As String() = configNamespace.Split("/"c) Dim currentNamespace As String = namespaceParts(0) ' 从root开始 For i As Integer = 1 To namespaceParts.Length - 1 currentNamespace = $"{currentNamespace}/{namespaceParts(i)}" Try ' 尝试连接命名空间,检查是否存在 Dim scope As New ManagementScope(currentNamespace) scope.Connect() Catch ex As ManagementException ' 命名空间不存在,创建它 Using nsClass As New ManagementClass($"root/__Namespace", Nothing) Using newNs As ManagementObject = nsClass.CreateInstance() newNs("Name") = namespaceParts(i) newNs.Put() End Using End Using End Try Next End If ' 保留你原来的注册表修改逻辑 If Context.Parameters.ContainsKey("configName") Then Dim system = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("System") Dim currentControlSet = system.OpenSubKey("CurrentControlSet") Dim services = currentControlSet.OpenSubKey("Services") Dim service = services.OpenSubKey(Me.ServiceInstaller1.ServiceName, True) service.SetValue("Description", Me.ServiceInstaller1.ServiceName + " Service") Dim config = service.CreateSubKey("Parameters") config.SetValue("Arguments", Command) Console.WriteLine(service.GetValue("ImagePath")) service.SetValue("ImagePath", $"{service.GetValue("ImagePath")} {Context.Parameters.Item("configName")}") End If End Sub
3. 在Windows服务的OnStart方法中动态初始化WMI
接下来,在你的服务主类的OnStart方法里,读取配置文件中的命名空间,手动初始化WMI instrumentation:
Imports System.Management.Instrumentation Imports System.Configuration Imports System.IO Public Class YourServiceClass Inherits ServiceBase Protected Overrides Sub OnStart(args() As String) ' 读取启动参数中的configName(来自ProjectInstaller设置的ImagePath) Dim configName As String = If(args.Length > 0, args(0), String.Empty) Dim namespaceName As String = "Root/EnRoute/Interfaces/Spill" ' 默认值 If Not String.IsNullOrEmpty(configName) Then ' 加载指定的配置文件 Dim configPath As String = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{configName}.config") Dim configMap As New ExeConfigurationFileMap() With {.ExeConfigFilename = configPath} Dim config As Configuration = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None) namespaceName = config.AppSettings.Settings("WmiNamespace")?.Value ?? namespaceName End If ' 动态初始化WMI instrumentation,指定命名空间 InstrumentationManager.Initialize(namespaceName, True) ' 注册你的WMI监测类(替换成你自己的WMI类型) InstrumentationManager.RegisterType(GetType(YourCustomWmiClass)) ' 其他服务启动逻辑... End Sub Protected Overrides Sub OnStop() ' 清理WMI instrumentation资源 InstrumentationManager.Shutdown() MyBase.OnStop() End Sub End Class
4. 配置文件中添加WmiNamespace项
在你的目标配置文件(比如EnRoute.Interface.Spill.<groupname>.Service.exe.config)里,添加命名空间的配置项:
<appSettings> <add key="WmiNamespace" value="Root/EnRoute/Interfaces/Spill_Law" /> </appSettings>
为什么不需要自定义InstrumentedAttribute?
你之前猜测的自定义构造器其实没必要,因为程序集级属性是编译时绑定的,运行时无法修改它的参数。而上面的方法通过手动创建WMI命名空间+运行时动态初始化Instrumentation,完全绕开了静态属性的限制,实现了动态配置的需求。
内容的提问来源于stack exchange,提问作者Brett Ossman
相关产品推荐
相关产品推荐

