我遇到了在.NET Windows服务中跨应用程序域编组对象的问题。
我创建了两个应用程序,它跨应用程序域封送对象并通过代理MarshalByRefObject
运行代码
第一个应用程序是一个简单的概念证明,因为我没有很多跨应用程序域编组的经验。它包含一个项目,其中MarshalByRefObject
在与项目其余部分相同的命名空间中定义。这个应用程序工作正常,使用与我的其他应用程序几乎相同的代码。主要区别在于我在第二个应用程序中编组的类是在另一个命名空间中定义的。
另一个项目更复杂,它是一个包含多个项目的Windows服务。主Windows服务加载一个执行编组的库。 Marshal目标类型的类类型在另一个库中定义,因此我使用完全限定的名称空间/类名。
我遇到的问题是当它到达下面代码的最后一行时会引发异常:
无法从程序集ProductNameService 加载CompanyName.ProductGroup.BusinessObjects.ProductName.MarshalByRefScriptCompiler,其中产品名称是主Windows服务类。
守则:
AppDomain compilerDomain = null;
AppDomainSetup compilerDomainSetup;
CompanyName.ProductGroup.BusinessObjects.ProductName.MarshalByRefScriptCompiler scriptCompiler;
...
// Setup a seperate AppDomain
compilerDomainSetup = new AppDomainSetup();
exeAssembly = Assembly.GetEntryAssembly().FullName;
compilerDomainSetup.ApplicationBase = System.Environment.CurrentDirectory;
compilerDomainSetup.DisallowBindingRedirects = false;
compilerDomainSetup.DisallowCodeDownload = true;
compilerDomainSetup.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
compilerDomain = AppDomain.CreateDomain("LiveLinkCSScriptDomain", null, compilerDomainSetup);
// Create an instance of the MarshalByRefScriptCompiler in the other AppDomain
scriptCompiler = (CompanyName.ProductGroup.BusinessObjects.ProductName.MarshalByRefScriptCompiler)compilerDomain.CreateInstanceAndUnwrap(exeAssembly, typeof(CompanyName.ProductGroup.BusinessObjects.ProductName.MarshalByRefScriptCompiler).FullName);
我已经对这个异常进行了研究,几乎所有我发现它都是DLL的版本化问题,但是我的DLL不在GAC中,并且没有安装其他版本。我正在进行干净的构建并使用installutil安装服务。
我使用MSDN documentation作为创建编组的代码的指南
我想知道加载MarshalByRefScriptCompiler
是否存在问题,因为该类型位于另一个库中。我可以在一个简单的winforms应用程序中创建一个MarshalByRefScriptCompiler
,但我在Windows服务中得到了异常。
非常感谢任何提示或见解!
答案 0 :(得分:2)
我应该能够帮到你。我最近花了很多时间(How do I pass references as method parameters across AppDomains?)处理不同的跨appdomain编组问题。我的第一个建议是尝试使用 CreateInstanceFromAndUnwrap 而不是 CreateInstanceAndUnwrap 。
我对这一行也有点警惕:
compilerDomainSetup.ApplicationBase = System.Environment.CurrentDirectory;
您的原始AppDomain是如何创建的?您是否在IIS中托管,在这种情况下,您的原始AppDomain将使用ShadowCopy?所有的dll都涉及一个文件夹吗?
编辑:
总而言之,如果 compilerDomainSetup.ApplicationBase 设置为包含dll的目录,并且传入了正确的第一个参数(例如typeof(MarshalByRefScriptCompiler),则可以使用 CreateInstanceAndUnwrap ).Assembly.FullName)。
或者,您可以使用 CreateInstanceFromAndUnwrap ,只需将包含程序集的位置(例如typeof(MarshalByRefScriptCompiler).Assembly.Location)作为第一个参数传递。
答案 1 :(得分:1)
作为一个起点,您可以尝试Process Monitor来确定它从哪里尝试加载您丢失的类型。它很可能就像查看错误的目录一样简单。