2011-07-22 23 views
17

ClickOnce是否只查看应用程序清单文件以确定要将哪些dll文件复制到客户机器,还是询问程序集的内部以确定相关性文件?ClickOnce - 文件已经存在错误 - 为什么DLL文件试图通过ClickOnce复制两次?

我问的原因是因为在尝试启动已使用ClickOnce发布的WPF .NET 4应用程序时,出现以下ClickOnce错误: 文件C:\Users\CNelson\AppData\Local\Temp\Deployment\PGX6P33A.35N\AJQL8AC8.D60\tx16_rtf.dll已存在。

这个错误开始于我已经引用了两个引用非托管dll文件(tx16_rtf.dll)的第三方.NET dll的引用。我想将tx16_rtf.dll复制到客户端PC上的bin文件夹中,以便将其包含在我的项目中,并将生成操作设置为“内容”,并将“复制到输出目录”设置为“始终复制”。

但是,由于某些原因,当我尝试启动应用程序时ClickOnce试图复制文件'tx16_rtf.dll'两次,这会导致错误。

如果我看看部署清单文件,我可以清楚地看到文件'tx16_rtf.dll'的一个条目。所以,我的问题是,为什么ClickOnce尝试复制文件'tx16_rtf.dll'两次,如果它只在部署清单文件中存在一次?

下面是部署清单文件中引用“tx16_rtf.dll”的一个片段:

<file name="tx16_rtf.dll" size="839680"> 
    <hash> 
     <dsig:Transforms> 
     <dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" /> 
     </dsig:Transforms> 
     <dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> 
     <dsig:DigestValue>V6i2QcARl3+1SJHCugoazb9zrOY=</dsig:DigestValue> 
    </hash> 
    </file> 
+0

你对这个问题的解决方案是什么? –

+0

我的解决方案是不参考我的项目中的非托管dll。因此,ClickOnce不会将它们包含在清单中。相反,我所做的是将非托管dll文件包含在一个zip文件中(将Build Action设置为'Content'),当我的应用程序启动时,它将解压非托管dll到正确的执行目录中......并且所有工作都像魅力。 – ChrisNel52

回答

10

在Visual Studio解决方案,如何在文件中添加?请尝试以下。

将dll添加到您的项目中。

如果你有引用的dll的引用,像这样设置dll的属性:Build Action = none,复制到输出目录=“不要复制”。然后删除引用,然后重新添加引用,但指向您的本地项目文件夹中的该dll。在参考中,将“copy local”设置为true。

如果您没有dll的引用,请像这样设置dll的属性:Build Action =“copy”。复制到输出目录=“始终复制”。

如果你有一个参考,你希望它被包含的原因是基于引用,而不是在dll属性。如果你没有参考,你需要专门设置dll来包含dll。

还检查应用程序文件对话框,并确保dll未标记为包含(先决条件),但是包含或包含(必需)。

+1

我使用mage.exe自动创建清单文件。我觉得我对ClickOnce和manifest文件有一个很好的理解,但ClickOnce在非托管dll中做了一些秘密的工作。然而,试图找到有关ClickOnce内部工作的详细文档似乎是不可能的。 – ChrisNel52

+0

RobinDotNet您的解释让我对我的重复的dll clickonce问题有了一个答案,所以我向你投了赞。 – TWood

+13

对不起,晚了,但为了搜索者的利益,我遇到了与Automapper.Net4.dll类似的问题。问题是我引用了'Automapper.Net4.dll'和'Automapper.dll'(后来我发现它引用了Net4.dll本身)。遵循上面的建议。删除了参考ClickOnce Complained about,删除了bin文件夹并重新构建了该项目。 Net 4 dll奇迹般地重新出现,所以不需要直接参考。之后没有使用ClickOnce probs。 – HockeyJ

8

如果您使用精彩的(咳嗽)MAGE.EXE来生成部署清单,则不提。不过,我遇到过相同的'The file x already exists'错误,并且它是由通过P/Invoke调用本地程序集中的函数的托管程序集引起的。

对于由MAGE.EXE的-FromDirectory参数指定的位置中的每个托管程序集,MAGE将创建一组<dependency><dependentAssembly>...</dependentAssembly></dependency>元素(包括程序集代码库,标识,大小,散列等)。对于每个其他文件(包括非托管本地程序集),MAGE.EXE将创建一个<file>...</file>元素。

但是在安装时,看起来ClickOnce实际上检查每个托管程序集的清单元数据。因此,如果您的应用程序具有ManagedAssemblyA(其中包含P/Invocation NativeAssemblyB中的代码)(您的案例中为tx16_rtf.dll),则您将通过ILDASM看到ManagedAssemblyA的清单具有.module extern NativeAssemblyB.dll语句。

我只能假定ClickOnce在处理<dependentAssembly codebase="ManagedAssemblyA.dll">元素的同时检查程序集的元数据,发现有一个本地程序集引用,它看到它也位于相同的部署位置并将其复制下来。然后,当稍后处理<file name="NativeAssemblyB.dll">元素时,它会发生错误,因为它已经复制了此文件,并假定未能安装是最安全的操作过程。我没有发现任何Microsoft记录的此行为。

所以解决方案是,在生成MAGE.EXE的部署清单之后,但在对其进行签名之前,请删除任何本机程序集的<file>元素。本地程序集仍然需要在ClickOnce应用程序所需的其他程序集相同的部署位置中可用。

在我们的例子中,我们的自动化这一点,因为我们还自动化部署的清单与各持续集成构建(而不是使用发布向导的Visual Studio 2010,让你多一点控制内)的产生;我们有一个Powershell脚本,它调用MAGE.EXE创建部署清单,还有一些Powershell来操纵XML并删除<file>元素(用Powershell很容易......用批处理文件做这件事很好!),然后我们调用MAGE.EXE签署清单。

+0

很好的回答!我将着眼于实施您的解决方案。 – ChrisNel52

0

整合您的NuGet包,如果你有2个引用依赖于不同版本的第三NuGet包的,有时你可以有2次对同一NuGet包。这将导致Clickonce失败。