Does ClickOnce only look at the application manifest file to determine which dll files to copy to the client’s machine or does it also interrogate the internals of an assembly to determine dependency files?
The reason I’m asking is because I’m getting the below ClickOnce error when trying to launch a WPF .NET 4 application that has been published with ClickOnce:
The file C:\Users\CNelson\AppData\Local\Temp\Deployment\PGX6P33A.35N\AJQL8AC8.D60\tx16_rtf.dll
already exists.
This error began after I’ve included a reference to two 3rd party .NET dlls tha开发者_如何学Pythont both reference an unmanaged dll file (tx16_rtf.dll). I want tx16_rtf.dll to be copied to the bin folder on the client’s PC so I have included it in my project and set the Build Action to ‘Content’ and the Copy to Output Directory to ‘Copy Always’.
However, for some reason when I try to launch the application ClickOnce is trying to copy the file ‘tx16_rtf.dll’ twice, which results in an error.
If I look at the deployment manifest file I can clearly see one and only one entry for file ‘tx16_rtf.dll’. So, my question is, why does ClickOnce try to copy file ‘tx16_rtf.dll’ twice if it only exists once in the deployment manifest file?
Below is a snippet of the deployment manifest file that references ‘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>
In your Visual Studio solution, how is the file added? Please try the following.
Add the dll to your project.
If you have a reference to the dll in References, set the properties on the dll like this: Build Action = none, Copy to output directory = "do not copy". Then delete the reference and then re-add the reference, but point to that dll in your local project folder. On the REference, set "copy local" to true.
If you don't have a Reference for the dll, set the properties on the dll like this: Build Action = "copy". Copy to Output Directory = "Copy always".
If you have a reference, you want the reason for it to be included to be based on the reference, and not on the dll properties. If you don't have a reference, you want to set the dll specifically to be included.
Also check the Application Files dialog and make sure the dll is not marked as Include(Prerequisite), but is Include or Include(Required).
You don't mention if you are using the wonderful (cough) MAGE.EXE to generate your deployment manifest. However I have encountered the same 'The file x already exists' error, and it is caused by managed assemblies that call functions in native assemblies via P/Invoke.
For each managed assembly in the location specified by the -FromDirectory argument to MAGE.EXE, MAGE will create a <dependency><dependentAssembly>...</dependentAssembly></dependency>
set of elements (including the assembly codebase, identity, size, hash, etc). For each other file (including non-managed native assemblies) MAGE.EXE will create a <file>...</file>
element.
However at install-time, it appears that ClickOnce actually inspects the manifest metadata of each managed assembly. So if your application has ManagedAssemblyA which P/Invokes code in NativeAssemblyB (or tx16_rtf.dll
in your case), you will see via ILDASM that the manifest for ManagedAssemblyA has a .module extern NativeAssemblyB.dll
statement.
I can only assume that ClickOnce, whilst processing the <dependentAssembly codebase="ManagedAssemblyA.dll">
element, inspects the assembly's metadata, sees that there is a native assembly referenced, sees that it is also in the same deployment location and copies it down. Then, when later processing the <file name="NativeAssemblyB.dll">
element, it errors as it has already copied this file and assumes failing to install is the safest course of action. I haven't found this behaviour documented by Microsoft anywhere.
So the solution is, after generating the deployment manifest with MAGE.EXE, but before signing it, remove the <file>
elements for any native assemblies. The native assemblies still need to be available in the same deployment location as the rest of the assemblies required by the ClickOnce app.
In our case we automated this since we also automate the generation of the deployment manifest with each continuous integration build (as opposed to using the Publishing Wizard inside Visual Studio 2010 which gives you a bit more control); we have a Powershell script that invokes MAGE.EXE to create the deployment manifest, some more Powershell to manipulate the XML and remove the <file>
element (really easy with Powershell... good luck doing it with a batch file!), then we invoke MAGE.EXE to sign the manifest.
Consolidate your nuget packages, if you have 2 references that depend on different versions of a 3rd nuget package, sometimes you can have 2 references to a same nuget package. This will cause Clickonce to fail.
This can also happen if you sometimes reference the .csproj and sometimes the compile .dll
E.g.:
Main.csproj:
ref A.csproj
ref B.csproj
A.csproj
ref B.dll
精彩评论