如果在 Windows 服务 .net 可执行文件中调用 .NET Assembly.Load/LoadFrom 会失败
Posted
技术标签:
【中文标题】如果在 Windows 服务 .net 可执行文件中调用 .NET Assembly.Load/LoadFrom 会失败【英文标题】:.NET Assembly.Load/LoadFrom fails if calling it within a windows service .net executable 【发布时间】:2019-12-13 11:57:24 【问题描述】:各位开发者好!
我目前在运行时在我的 WPF 应用程序中使用“Assembly.Load”或“Assembly.LoadFrom”加载特定程序集时有点迷失了。 p>
如果我只运行可执行文件,则在运行时加载程序集就可以了!
但是它会抛出异常“FileNotFoundException,无法加载文件或程序集..或其依赖项之一..” 如果我以相同的方式加载相同的程序集,而我的 WPF 应用程序作为 windows 服务(在 LocalSystem 下)运行。
processInstaller.Account = ServiceAccount.LocalSystem;
processInstaller.Username = null;
processInstaller.Password = null;
导致异常的程序集称为“Siemens.Sinumerik.Operate.Services.Wrapper.dll”,由“Siemens.Sinumerik.Operate.Services.dll”。
-> 3rd 方程序集 - 没有可用的源,对我来说,包装器似乎是一个混合的 cli/c++ 程序集。
现在,在对这个问题进行一些研究后,我发现 .e.g 可能程序集的查找目录是“C:\windows\system32”,而不是存储可执行文件的文件夹。或者采取“fuslogvw”来缩小问题范围。
然而,它不是我的第一个项目在运行时加载程序集以执行某些操作。唯一的事情是我在运行时从未加载过混合的“cli/c++”程序集 -> 可能有任何已知问题或我可能会错过正确加载“cli/c++”程序集的内容?
这是我用来加载程序集的代码(来自文件或 gac)
LoadAssembly("Siemens.Sinumerik.Operate.Services"); // this assembly references the wrapper
LoadAssembly("Siemens.Sinumerik.Operate.Services.Wrapper, Version=4.8.2.0, Culture=neutral, PublicKeyToken=bdd90fa02fd1c4ee", false); // load the wrapper from GAC using AssemblyName -> Exception only in service
LoadAssembly("Siemens.Sinumerik.Operate.Services.Wrapper"); // load the wrapper from file using AssemblyName -> Exception only in service
LoadAssembly 正在检查 AssemblyName 是否已经加载到当前 AppDomain 中,如果没有,则使用 GAC 或 FileSystem 加载它(取决于函数 LoadAssembly 的第二个参数“loadFromFile”)。
因此它使用"Assembly.Load(assemblyName); // from gac"
或"Assembly.LoadFrom(file); // from file"
我尝试解决的问题:
将动态加载的程序集引用到主项目,希望应用程序能够在启动期间将包装程序集加载到 AppDomain -> 失败
将当前目录更改为存储包装程序集 dll 的路径 -> 失败
连接所有 AssemblyLoad 和 Resolve 事件并尝试使用“Assembly.Load”加载 -> fail
比较了用于服务和普通可执行文件的 AppDomains -> 似乎两者都一样,没有看到它们之间有任何特殊区别)-> 失败
李>使用“fuslogvw”获取一些可能指示任何错误的程序集绑定信息 -> 失败(请参阅下面的日志)
此外,我使用“fuslogvw”来找出包装器到底出了什么问题,但我没有得到任何线索,因为日志显示的结果与我只是运行正常的可执行文件一样(不能作为服务工作) 这是日志“Siemens.Sinumerik.Operate.Services.Wrapper, Version=4.8.2.0, Culture=neutral, PublicKeyToken=bdd90fa02fd1c4ee.HTM”:
*** Protokolleintrag für Assembly-Binder (13.12.2019 @ 12:12:21) ***
Der Vorgang wurde durchgeführt.
Ergebnis der Bindung: hr = 0x0. Der Vorgang wurde erfolgreich beendet.
Der Assemblymanager wurde geladen aus: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Als EXE-Datei ausgeführt. C:\Projekte\MTF\trunk\MTFMain\MTF\bin\Debug\MTF.exe
--- Ein detailliertes Fehlerprotokoll folgt.
=== Zustandsinformationen vor Bindung ===
LOG: DisplayName = Siemens.Sinumerik.Operate.Services.Wrapper, Version=4.8.2.0, Culture=neutral, PublicKeyToken=bdd90fa02fd1c4ee
(Fully-specified)
LOG: Appbase = file:///C:/Projekte/MTF/trunk/MTFMain/MTF/bin/Debug/
LOG: Ursprünglicher PrivatePath = NULL
LOG: DynamicBase = NULL
LOG: CacheBase = NULL
LOG: AppName = MTF.exe
Aufruf von Assembly : MTF, Version=2.0.7286.21871, Culture=neutral, PublicKeyToken=null.
===
LOG: Diese Bindung startet im default-Load-Kontext.
LOG: Die Anwendungskonfigurationsdatei wird verwendet: C:\Projekte\MTF\trunk\MTFMain\MTF\bin\Debug\MTF.exe.Config
LOG: Die Hostkonfigurationsdatei wird verwendet:
LOG: Die Computerkonfigurationsdatei von C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config wird verwendet.
LOG: Verweis nach der Richtlinie: Siemens.Sinumerik.Operate.Services.Wrapper, Version=4.8.2.0, Culture=neutral, PublicKeyToken=bdd90fa02fd1c4ee
LOG: Die Assembly wurde bei Suche im GAC gefunden.
LOG: Die Bindung war erfolgreich. Assembly wird zurückgegeben von C:\Windows\assembly\GAC_32\Siemens.Sinumerik.Operate.Services.Wrapper\4.8.2.0__bdd90fa02fd1c4ee\Siemens.Sinumerik.Operate.Services.Wrapper.dll.
LOG: Die Assembly wird im default-Load-Kontext geladen.
这里是“WhereRefBind!Host=(LocalMachine)!FileName=(Siemens.Sinumerik.Operate.Services.Wrapper.dll).HTM”:
*** Protokolleintrag für Assembly-Binder (13.12.2019 @ 12:14:00) ***
Der Vorgang wurde durchgeführt.
Ergebnis der Bindung: hr = 0x0. Der Vorgang wurde erfolgreich beendet.
Der Assemblymanager wurde geladen aus: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Als EXE-Datei ausgeführt. C:\Projekte\MTF\trunk\MTFMain\MTF\bin\Debug\MTF.exe
--- Ein detailliertes Fehlerprotokoll folgt.
=== Zustandsinformationen vor Bindung ===
LOG: Where-ref-Bindung. Speicherort = C:\Projekte\MTF\trunk\MTFMain\MTF\bin\Debug\dll\Siemens.Sinumerik.Operate.Services.Wrapper.dll
LOG: Appbase = file:///C:/Projekte/MTF/trunk/MTFMain/MTF/bin/Debug/
LOG: Ursprünglicher PrivatePath = NULL
LOG: DynamicBase = NULL
LOG: CacheBase = NULL
LOG: AppName = MTF.exe
Aufruf von Assembly : (Unknown).
===
LOG: Diese Bindung startet im LoadFrom-Load-Kontext.
WRN: Das native Image wird nicht im LoadFrom-Kontext durchsucht. Das native Image wird nur im Standard-Load-Kontext durchsucht, z. B. Assembly.Load().
LOG: Die Anwendungskonfigurationsdatei wird verwendet: C:\Projekte\MTF\trunk\MTFMain\MTF\bin\Debug\MTF.exe.Config
LOG: Die Hostkonfigurationsdatei wird verwendet:
LOG: Die Computerkonfigurationsdatei von C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config wird verwendet.
LOG: Download von neuem URL file:///C:/Projekte/MTF/trunk/MTFMain/MTF/bin/Debug/dll/Siemens.Sinumerik.Operate.Services.Wrapper.dll.
LOG: Der Assembly-Download wurde durchgeführt. Datei-Setup wird begonnen: C:\Projekte\MTF\trunk\MTFMain\MTF\bin\Debug\dll\Siemens.Sinumerik.Operate.Services.Wrapper.dll.
LOG: Die von der Quelle ausgeführte Setup-Phase beginnt.
LOG: Der Assemblyname ist: Siemens.Sinumerik.Operate.Services.Wrapper, Version=4.8.2.0, Culture=neutral, PublicKeyToken=bdd90fa02fd1c4ee.
LOG: Die Richtlinie wird für where-ref-Bindung erneut angewendet.
LOG: Verweis nach der Richtlinie: Siemens.Sinumerik.Operate.Services.Wrapper, Version=4.8.2.0, Culture=neutral, PublicKeyToken=bdd90fa02fd1c4ee
LOG: Die Assembly wurde bei Suche im GAC gefunden.
LOG: Wechseln vom LoadFrom-Kontext zum Standardkontext.
LOG: Die Bindung war erfolgreich. Assembly wird zurückgegeben von C:\Windows\assembly\GAC_32\Siemens.Sinumerik.Operate.Services.Wrapper\4.8.2.0__bdd90fa02fd1c4ee\Siemens.Sinumerik.Operate.Services.Wrapper.dll.
LOG: Die Assembly wird im default-Load-Kontext geladen.
我希望有人可以帮助我缩小 Wrapper 程序集的加载问题 :) 或者有任何其他想法我可以做什么..
到目前为止谢谢! 如果您需要更多信息,请告诉我!
【问题讨论】:
您可能需要在 Windows 服务在其他位置运行的 AppDomain.CurrentDomain.BaseDirectory 中找到 DLL 嘿,我已经将基目录设置为可执行文件的路径。就像你在“fuslogvw”中看到的那样LOG: Appbase = file:///C:/Projekte/MTF/trunk/MTFMain/MTF/bin/Debug/
【参考方案1】:
根本原因: 该问题是由于并非所有本机 dll(使用提及包装器)都可以为“LocalSystem”帐户解决。
重点是 Wrapper 需要设置 3 个特定路径来查找本机 dll,例如“QT”库,.. 我在第一次安装这个“Siemens”API 时做了一次,但是当安装映射它的安装文件夹和一个额外的驱动器号时,我在 %PATHS% 变量中添加了这 3 个额外的路径使用新创建的驱动器号-> 这是一个大问题,因为用户“LocalSystem”无法访问我的虚拟机?驱动器“D:” -> 因此 %PATH% 变量中的路径无法“解析”,因为驱动器“D:”没有退出。
解决方案:更改了 %PATH% 变量中的 3 个特定路径,以确保它现在指向“C:..”下的安装文件夹!
附加: 工具“procmon”是查看无法解析那些原生 c/c++ 库的唯一方法。 我在搜索时检查了工具列出的所有路径,例如“QtCore4.dll”(作为服务运行时)。
-> 通常:如果无法解析本机库,则使用“Assembly.Load”加载的 .NET 程序集不会引发任何“AssemblyResolve”事件。
-> Fuslogvw 在这个级别无法提供帮助,因为它没有提供有关本机库的详细信息。
结案:)
【讨论】:
以上是关于如果在 Windows 服务 .net 可执行文件中调用 .NET Assembly.Load/LoadFrom 会失败的主要内容,如果未能解决你的问题,请参考以下文章