我有一个单独的.Net 4应用程序来远程升级主应用程序(功能)。由于最近的更改,它现在与主应用程序共享对同一文件的引用。这当然可以防止它复制覆盖该文件的新dll(基本上是dll,除其他外,处理设置 - 我需要从中检索一些数据,以防止不加载它)。通过SO浏览我认为我已经设法进一步,但现在已经遇到了障碍。
我尝试从资源加载dll(由于应用程序从应用程序目录中找到较旧的common.dll而无效,如果我从资源加载,那么同一dll的两个不同版本之间存在类型冲突)。因为似乎没有任何方法可以更改默认应用程序域的DisallowApplicationBaseProbing设置(以防止从目录中加载旧的common.dll),所以我创建了启动器应用程序,它将使用该选项集启动升级到新创建的应用程序域。为了防止启动器通过引用升级程序获取对设置文件的引用,我将两者都包含为资源(如果直接引用,它的子引用会导致从应用程序目录加载文件并阻止复制(见文件),你可以在下面看到 - 我有类似的其他配置块。
<When Condition=" '$(Configuration)' == 'Debug' ">
<ItemGroup>
<EmbeddedResource Include="..\..\Libraries\Common\bin\Debug\Common.dll">
<Link>Common.dll</Link>
</EmbeddedResource>
<EmbeddedResource Include="..\..\Deployment\Upgrader\bin\Debug\Upgrader.dll">
<Link>Upgrader.dll</Link>
</EmbeddedResource>
</ItemGroup>
</When>
据我所知,正确的dll将被选入资源。在启动器中,我有以下代码(它确实找到了数据,之前已正确加载文件 - 但现在已经崩溃了)。
Console.WriteLine("Setting up AppDomain..");
var setup = AppDomain.CurrentDomain.SetupInformation;
setup.DisallowApplicationBaseProbing = true;
createdDomain = AppDomain.CreateDomain("CorrectedCommonDomain", null, setup);
using (Stream s = Assembly.GetEntryAssembly().GetManifestResourceStream("UpgraderLauncher.Common.dll"))
{
if (s == null)
{
Console.WriteLine("Could not load common.dll correctly!");
throw new ArgumentNullException("Could not load internal common.dll resource.");
}
Console.WriteLine("Loading common.dll..");
byte[] data = new byte[s.Length];
s.Read(data, 0, data.Length);
commonDllAssembly = createdDomain.Load(data);
Console.WriteLine("Loading common.dll is done.");
}
问题出现在&#34; createdDomain.Load(data);&#34; part,抛出FileLoadException(HResult 0x80131040 aka manifest error)。完整的例外情况如下。
未处理的类型&#39; System.IO.FileLoadException&#39;发生在UpgraderLauncher.exe
中其他信息:无法加载文件或程序集&#39; Common,Version = 1.0.5256.21424,Culture = neutral,PublicKeyToken = 86e85f643d1e5711&#39;或其中一个依赖项。定位的程序集的清单定义与程序集引用不匹配。 (HRESULT异常:0x80131040)
重建common.dll(以及随后的启动器)后,将更新异常消息中的dll版本。我该如何进行,字节加载的dll的清单如何与自身不同? (所有文件都经过强烈签名。)
答案 0 :(得分:0)
好的,我解决了这个问题。问题是程序集被加载到两个域中(因为在启动程序中有一个对程序集的引用,它也被加载到默认的AppDomain,而不是加载它所要求的dll而是继续加载清单启动程序所在目录中的旧文件,从而以旧文件和启动程序中包含的字节之间的清单冲突结束。 要在类似情况下解决错误,而不是在默认AppDomain中加载任何代码加载文件,请将加载移动到创建的AppDomain中。为此,请将byte []保存到appdomain数据:
createdDomain.SetData("CommonDllAssembly", data);
然后在创建的域上运行的代码中:
byte[] bytes = AppDomain.CurrentDomain.GetData("CommonDllAssembly") as byte[];
commonDllAssembly = Assembly.Load(bytes);
这可以防止弹出上述错误。