Installutil.exe忽略.exe.config致程序集加载失败的解决方法
故障原因
installutil.exe是独立的可执行程序,运行时默认加载同目录下的installutil.exe.config作为运行时配置,不会自动读取待安装Service.exe同目录的配置文件,因此你配置的私有程序集探测路径在安装阶段不生效,加载服务程序集时找不到子目录下的依赖就会抛出ReflectionTypeLoadException。
注意:你当前的probing路径配置存在错误:privatePath必须填写相对于exe根目录的完整相对路径,module_libraries下的子目录不能直接写subfolder1,要写成module_libraries/subfolder1,否则程序运行时也可能出现偶发的程序集加载失败。
你的服务目录结构参考:
+---config +---executable +---thirdparty_libraries +---icons +---helper_libraries +---module_libraries ¦ +---subfolder1 ¦ +---... +---support +---temp
原有可正常运行的配置参考(修正后):
<?xml version ="1.0"?> <configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <probing privatePath=" executable; support; helper_libraries; thirdparty_libraries; module_libraries; module_libraries/subfolder1; ... "/> </assemblyBinding> <generatePublisherEvidence enabled="false" /> </runtime> </configuration>
安装阶段抛出的典型报错:
Exception whilst searching for the Installer in Assembly ...\Service.exe System.Reflection.ReflectionTypeLoadException: At least one Type in the Assembly cannot be loaded.
可用解决方案
方案1:临时修改installutil配置(最快,适合临时安装)
- 定位你当前调用的
installutil.exe路径:VS2017对应的64位版本默认路径是C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe,32位版本在C:\Windows\Microsoft.NET\Framework\v4.0.30319\目录下。 - 在同目录下找到/新建
installutil.exe.config文件,把Service.exe.config中<runtime>节点下的所有配置(包括assemblyBinding、probing路径、generatePublisherEvidence配置)完整复制进去,注意修正前面提到的子目录路径写法。 - 保存后重新执行安装命令即可。安装完成后可以删掉你加在
installutil.exe.config里的内容,避免影响其他服务的安装。
方案2:实现服务自安装(最稳定,长期推荐)
完全不依赖外部的installutil,把安装逻辑集成到服务程序自身,从根源避免配置不生效问题:
- 在服务项目中引用
System.ServiceProcess和System.Configuration.Install程序集,添加如下自安装逻辑,通过命令行参数触发安装/卸载:
using System; using System.Configuration.Install; using System.Reflection; using System.ServiceProcess; [RunInstaller(true)] public class ServiceSelfInstaller : Installer { private readonly ServiceProcessInstaller _processInstaller; private readonly ServiceInstaller _serviceInstaller; public ServiceSelfInstaller() { _processInstaller = new ServiceProcessInstaller { Account = ServiceAccount.LocalSystem // 按需修改服务运行账户 }; _serviceInstaller = new ServiceInstaller { ServiceName = "YourServiceName", // 替换为你的服务名 DisplayName = "你的服务显示名", StartType = ServiceStartMode.Automatic, // 按需修改启动类型 Description = "服务描述" }; Installers.Add(_processInstaller); Installers.Add(_serviceInstaller); } public static void Main(string[] args) { if (args.Length > 0) { switch (args[0].ToLower()) { case "-install": ManagedInstallerClass.InstallHelper(new[] { Assembly.GetExecutingAssembly().Location }); return; case "-uninstall": ManagedInstallerClass.InstallHelper(new[] { "/u", Assembly.GetExecutingAssembly().Location }); return; } } // 原有服务运行逻辑 ServiceBase.Run(new YourActualServiceClass()); // 替换为你自己的服务类 } }
- 编译后直接以管理员身份在服务目录下执行
Service.exe -install即可完成安装,执行Service.exe -uninstall即可卸载。因为程序直接启动自身,会自动读取同目录下的Service.exe.config配置,不会出现依赖找不到的问题。
方案3:临时复制依赖完成安装(适合快速测试)
- 把所有子目录下的dll临时复制到
Service.exe所在的根目录,执行installutil安装完成后,再把根目录下复制出来的dll删掉即可。服务启动时会读取自身配置从子目录加载依赖,不影响后续运行。
内容的提问来源于stack exchange,提问作者CodingWolf
相关产品推荐
相关产品推荐

