C# Windows 服务 - 无法从相对路径加载外部类库
Posted
技术标签:
【中文标题】C# Windows 服务 - 无法从相对路径加载外部类库【英文标题】:C# Windows Service - Cannot load external Class Library from Relative Path 【发布时间】:2017-10-16 02:08:37 【问题描述】:我有一个 Windows 服务正在传递一个完全限定的方法名称。然后,它使用此名称在它恰好位于的任何外部 DLL 中查找适当的方法。我的服务引用了此 DLL,当我以硬编码方式引用和加载 DLL 时,一切似乎都正常工作:
var DLL = Assembly.LoadFile(@"C:\Users\ishiim\Desktop\TFS\IRSystem\Technical Utilities\Monitoring\TestModules\PingerTests\PingerTests\bin\Debug\PingerTests.dll");
Type type = DLL.GetExportedTypes()[0];
但是,我不会提前知道这些 DLL 的确切位置,当然,在这个示例中,我正在加载在解决方案目录中生成的 dll,而当服务在它已安装。
我要做的只是从服务当前运行的目录中按程序集名称加载 dll - 事实上,在我的 bin/debug 文件夹中,dll 就在那里。但是当我尝试使用完全限定的程序集名称从本地目录加载它时,类型返回 null:
// Example type TestModuleNamespace.TestModuleClassName
// Example assembly name TestModuleClassName (They are the same in my case)
Type type = Type.GetType(typeName + ", " + assemblyName);
我应该提到,在前面的代码 sn-p 中,当类库与我的服务在同一个解决方案中时,代码运行良好,但现在我已经将两者分开,这种方法将不再有效,并且类型返回 null。
我什至尝试使用使用当前执行目录的代码(据称是 C:\Windows\System32,即使服务 exe 不存在)加载 DLL,但这也没有成功:
Assembly serviceAssembly = Assembly.LoadFrom(Path.Combine(Environment.CurrentDirectory, assemblyName + ".dll"));
AssemblyName[] referencedAssemblies = serviceAssembly.GetReferencedAssemblies();
List<Assembly> assemblyLst = AppDomain.CurrentDomain.GetAssemblies().ToList();
foreach (AssemblyName name in referencedAssemblies)
Assembly.Load(name);
关于这个问题有很多答案,但我无法理解它们,因为我是 C# 和 .NET 的新手。我最大的困惑就是——如果在我的服务中引用了一个外部 DLL,然后将该 DLL 与该服务一起复制到 bin 目录中,那么在安装该服务时,为什么必须“加载”该 DLL 和如果它应该在同一个目录中,为什么它不能在当前的“路径”中找到它?
这感觉比它应该的更难,这很可能是由于我对如何在运行时加载程序集缺乏了解。 (库、DLLS,这些词似乎出于某种原因可以互换使用——真正的术语是什么?)
编辑 ---------------------------------- --
我觉得我对我正在尝试做的事情造成了一些混乱。我的程序执行以下操作:
1-获取包含完全限定方法名称的任务列表 2-通过反射在它所在的任何DLL中调用该方法并返回值
我的程序不知道这些 DLL 及其方法名称。它们被传入。我可以在编译时引用这些库,因为其他开发人员将编写它们,但至于何时调用它们,以及将调用什么方法,在我的服务之前完全未知。
看来我有两个选择: 1-对我给出的每个可能被调用的 DLL 进行引用,并通过使用完全限定的程序集名称进行反射调用来获取类型 2-将所有 DLL 放在一个已知位置,并通过它们在文件系统上的确切路径位置加载它们,并通过反射调用它们。
当 dll 在与我的服务相同的解决方案中开发和编译时,解决方案 1 正在工作。第二次我将 dll 移到自己的解决方案中,这段代码 Type type = Type.GetType(typeName + ", " + assemblyName);
开始返回 null。
解决方案 2 也很好,但是我似乎无法使用相对路径调用程序集。我必须存储执行程序集(我的服务)的当前路径,然后将其附加到目标程序集名称以获取类型,然后使用反射来调用该方法。这种方式对我来说似乎很丑陋,但就这样吧。
再编辑一次 ---
这就是我最终要做的。我非常讨厌这个,我不明白如果我已经做了参考,为什么我必须再次加载组件,但这有效:
String path = System.Reflection.Assembly.GetExecutingAssembly().Location;
testModuleLocation = System.IO.Path.GetDirectoryName(path);
Assembly asm = Assembly.LoadFile(System.IO.Path.Combine(testModuleLocation, assemblyName + DLL_FILE_EXT));
Type type = asm.GetExportedTypes()[0];
object instance = Activator.CreateInstance(type);
MethodInfo method = type.GetMethod(methodName);
method.Invoke(instance, arguments);
“TestModuleLocation”是我的服务的某个子文件夹,当我构建并安装服务时,我必须将所有 DLL 转储到其中。
我认为有很多关于“DLL”的内容不仅仅是一个库,而且绝不像我使用的任何其他语言那样工作。我想我需要做很多研究来重新了解库在 Windows 机器上的工作方式。
【问题讨论】:
C# - Correct Way to Load Assembly, Find Class and Call Run() Method的可能重复 为什么不直接使用引用而不是 Assembly.Load?我问是因为你写了if an external DLL is referenced in my service
。
因为直到运行时我才知道要调用什么 - 完全限定的方法名称由数据库对象传递给我。
不知道您需要使用的方法名称与不知道您将使用什么程序集不同。
为什么要在 ExecutingAssembly 上使用 GetExportedTypes?这会迭代公开可用的类型(您已经可以直接访问)。我本来希望serviceAssembly = Assembly.GetExecutingAssembly() ;
然后serviceAssembly.GetReferencedAssemblies();
然后使用反射来加载你的类型。除非你这样做而我误解了
【参考方案1】:
您可以获取可执行文件的路径并将当前目录设置为它。以下是如何做到这一点的示例:
String path = System.Reflection.Assembly.GetExecutingAssembly().Location;
path = System.IO.Path.GetDirectoryName(path);
Directory.SetCurrentDirectory(path);
将 Dll 存储在您的服务可执行文件的安装文件夹中,并且您的相对路径将在此步骤之后起作用。
【讨论】:
我已使用 Visual Studio 2015 安装程序组件来安装我的服务 - 因此使用了一些默认位置。看来我需要先了解如何指定安装文件夹,然后才能尝试使用此方法。一旦我弄清楚了,我会回来检查的。 您好 Petrosov 先生 - 当我尝试此操作时,只需在 assemblyname.dll 上调用 Assembly.Load - 我得到一个异常“System.ArgumentException:需要绝对路径信息。在 System.Security。 Util.StringExpressionSet.CreateListFromExpressions(String[] str, Boolean needFullPath)" 查看我的第二次编辑 - 我最终使用了这种方法。感觉不对,因为我已经在我的服务中引用了 dll,但我想这样我就不必再这样做了——我想。以上是关于C# Windows 服务 - 无法从相对路径加载外部类库的主要内容,如果未能解决你的问题,请参考以下文章
angular 2组件无法从外部css皮肤加载相对背景图像url
PyQt5 技巧篇-解决相对路径无法加载图片问题,styleSheet通过"相对"路径加载图片,python获取当前运行文件的绝对路径。
React 页面无法通过带有相对文件路径的 JSON 加载图像
在使用opencv中ClassifierCascade类时,无法加载级联分类器,相对路径和绝对路径都无法加载成功,why??