Publish a ClickOnce deploy with Visual Studio and assemblies not referenced

When you build a ClickOnce deploy Visual Studio do not get assemblies not referenced in the project or any other dependent project. Basically the problem are assemblies located in other folders than the project folder.

But you can workaround this issue overriding two targets in your project, both targets are located in Microsoft.Common.Targets. The basic idea is generate a new target file that your project references.

The first target is _DeploymentComputeClickOnceManifestInfo, which is executed before the beginning of the publishing. Copy this target to a file called Customized.targets, and add your logic in order to include the assemblies that Visual Studio do not include.

For example if want to include all the assemblies located in the modules subfolder we need to add the following tasks:

<Target Name="_DeploymentComputeClickOnceManifestInfo"
 Condition="'$(GenerateClickOnceManifests)'=='true'"
 DependsOnTargets="_DeploymentGenerateTrustInfo">
 <CreateItem Include="@(_ReferenceSerializationAssemblyPaths)"
 Condition="'%(Extension)' == '.dll'">
 <Output TaskParameter="Include" ItemName="_SGenDllsRelatedToCurrentDll0" />
 </CreateItem>
A0A0A0 <CreateItem Include="@(_SGenDllsRelatedToCurrentDll0->'%(FullPath)')">
A0A0A0A0A0A0A0 <Output TaskParameter="Include" ItemName="_SGenDllsRelatedToCurrentDll" />
A0A0A0 </CreateItem>
A0A0A0 <CreateItem Include="@(ReferencePath)" AdditionalMetadata="IsPrimary=true" >
A0A0A0A0A0A0A0 <Output TaskParameter="Include" ItemName="_DeploymentReferencePaths"/>
A0A0A0 </CreateItem>
A0A0A0 <ResolveManifestFiles
  EntryPoint="@(_DeploymentManifestEntryPoint)"
 ExtraFiles="$(IntermediateOutputPath)$(TargetName).pdb;$(IntermediateOutputPath)
 $(TargetName).xml;@(_ReferenceRelatedPaths)"
 Files="@(ContentWithTargetPath);@(_DeploymentManifestIconFile);@(AppConfigWithTargetPath)"
 ManagedAssemblies="@(_DeploymentReferencePaths);@(ReferenceDependencyPaths);
 @(_SGenDllsRelatedToCurrentDll)"
 NativeAssemblies="@(NativeReferenceFile);@(_DeploymentNativePrerequisite)"
 PublishFiles="@(PublishFile)"
 SatelliteAssemblies="@(IntermediateSatelliteAssembliesWithTargetPath);@(ReferenceSatellitePaths)"
 TargetCulture="$(TargetCulture)">
A0A0A0 <Output TaskParameter="OutputAssemblies" ItemName="_DeploymentManifestDependencies"/>
A0A0A0 <Output TaskParameter="OutputFiles" ItemName="_DeploymentManifestFiles"/>
A0A0A0 </ResolveManifestFiles>
A0
A0A0A0 <!-- Generate all dependencies -->
A0A0A0 <CreateItem Include="$(OutputPath)Modules\**\*.dll">
A0A0A0A0A0A0A0 <Output TaskParameter="Include" ItemName="DeploymentManifestModules" />
A0A0A0 </CreateItem>
A0A0A0 <CreateItem Include="@(DeploymentManifestModules)"
 AdditionalMetadata="TargetPath=Modules\%(RecursiveDir)
 %(Filename)%(Extension);DependencyType=Install">
A0A0A0A0 <Output ItemName="_DeploymentManifestDependencies" TaskParameter="Include" />
A0A0A0A0A0A0A0 </CreateItem>
A0A0A0A0A0A0A0 <!-- Generate all remaining files -->
A0A0A0A0A0A0A0 <CreateItem Include="$(OutputPath)Modules\**\*.xaml">
A0A0A0A0A0A0A0A0A0A0A0 <Output TaskParameter="Include" ItemName="LocalDeploymentManifestFiles" />
A0A0A0A0A0A0A0 </CreateItem>
A0A0A0A0A0A0A0 <CreateItem Include="@(LocalDeploymentManifestFiles)"
A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0 AdditionalMetadata="TargetPath=Modules\%(RecursiveDir)%(Filename)%(Extension)">
A0A0A0A0A0A0A0A0A0A0A0 <Output ItemName="_DeploymentManifestFiles" TaskParameter="Include" />
A0A0A0A0A0A0A0 </CreateItem>
A0
A0A0A0A0A0A0A0 <CreateProperty Value="ClickOnce">
A0A0A0A0A0A0A0A0A0A0A0 <Output TaskParameter="Value" PropertyName="_DeploymentManifestType"/>
A0A0A0A0A0A0A0 </CreateProperty>
A0
A0A0A0A0A0A0A0 <FormatVersion Version="$(ApplicationVersion)" Revision="$(ApplicationRevision)">
A0A0A0A0A0A0A0A0A0A0A0 <Output TaskParameter="OutputVersion" PropertyName="_DeploymentManifestVersion"/>
A0A0A0A0A0A0A0 </FormatVersion>
A0A0A0A0A0A0A0 <FormatUrl InputUrl="$(_DeploymentUrl)">
A0A0A0A0A0A0A0A0A0A0A0 <Output TaskParameter="OutputUrl" PropertyName="_DeploymentFormattedDeploymentUrl"/>
A0A0A0A0A0A0A0 </FormatUrl>
A0A0A0A0A0A0A0 <FormatUrl InputUrl="$(SupportUrl)">
A0A0A0A0A0A0A0A0A0A0A0 <Output TaskParameter="OutputUrl" PropertyName="_DeploymentFormattedSupportUrl"/>
A0A0A0A0A0A0A0 </FormatUrl>
A0A0A0 </Target>

The lines added to the original target are in italic format.

The second target to override is _CopyFilesToPublishFolder, the change here is easy, simply add the metadata variable %(RecursiveDir) for each item list that you want to copy.

A0A0A0 <Target Name="_CopyFilesToPublishFolder">
A0A0A0A0A0A0A0 <FormatVersion Version="$(ApplicationVersion)" Revision="$(ApplicationRevision)"
  FormatType="Path">
A0A0A0A0A0A0A0A0A0A0A0 <Output TaskParameter="OutputVersion"
  PropertyName="_DeploymentApplicationVersionFragment"/>
A0A0A0A0A0A0A0 </FormatVersion>
A0A0A0A0A0A0A0 <CreateProperty Value="$(AssemblyName)_$(_DeploymentApplicationVersionFragment)">
A0A0A0A0A0A0A0A0A0A0A0 <Output TaskParameter="Value" PropertyName="_DeploymentApplicationFolderName" />
A0A0A0A0A0A0A0 </CreateProperty>
A0A0A0A0A0A0A0 <CreateProperty Value="$(PublishDir)$(_DeploymentApplicationFolderName)\">
A0A0A0A0A0A0A0A0A0A0A0 <Output TaskParameter="Value" PropertyName="_DeploymentApplicationDir" />
A0A0A0A0A0A0A0 </CreateProperty>
A0
A0A0A0A0A0A0A0 <!-- Copy files to publish folder -->
A0A0A0A0A0A0A0 <Copy
A0A0A0A0A0A0A0A0A0A0A0 SourceFiles=
A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0 "@(_ApplicationManifestFinal);
A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0 @(_DeploymentManifestEntryPoint);
A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0 @(_DeploymentManifestFiles);
A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0 @(ReferenceComWrappersToCopyLocal);
A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0 @(ResolvedIsolatedComModules);
A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0 @(_DeploymentLooseManifestFile)"
A0A0A0A0A0A0A0A0A0A0A0 DestinationFiles=
A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0 "@(_ApplicationManifestFinal->'$(_DeploymentApplicationDir)
 %(TargetPath)%(RecursiveDir)');
A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0 @(_DeploymentManifestEntryPoint->'$(_DeploymentApplicationDir)
 %(TargetPath)%(RecursiveDir)$(_DeploymentFileMappingExtension)');
A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0 @(_DeploymentManifestFiles->'$(_DeploymentApplicationDir)
 %(TargetPath)%(RecursiveDir)$(_DeploymentFileMappingExtension)');
A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0 @(ReferenceComWrappersToCopyLocal->'$(_DeploymentApplicationDir)
 %(RecursiveDir)%(FileName)%(Extension)$(_DeploymentFileMappingExtension)');
A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0 @(ResolvedIsolatedComModules->'$(_DeploymentApplicationDir)
 %(RecursiveDir)%(FileName)%(Extension)$(_DeploymentFileMappingExtension)');
A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0 @(_DeploymentLooseManifestFile->'$(_DeploymentApplicationDir)
 %(RecursiveDir)%(FileName)%(Extension)$(_DeploymentFileMappingExtension)')"
A0A0A0A0A0A0A0A0A0A0A0 SkipUnchangedFiles="true"/>
A0
A0A0A0A0A0A0A0 <Copy
A0A0A0A0A0A0A0A0A0A0A0 SourceFiles="@(_DeploymentManifestDependencies)"
A0A0A0A0A0A0A0A0A0A0A0 DestinationFiles="@(_DeploymentManifestDependencies->
 '$(_DeploymentApplicationDir)%(TargetPath)$(_DeploymentFileMappingExtension)')"
A0A0A0A0A0A0A0A0A0A0A0 SkipUnchangedFiles="true"
A0A0A0A0A0A0A0A0A0A0A0 Condition="'%(_DeploymentManifestDependencies.DependencyType)'=='Install'"/>
A0A0A0A0A0A0A0 <Copy
A0A0A0A0A0A0A0A0A0A0A0 SourceFiles="@(_ReferenceScatterPaths)"
A0A0A0A0A0A0A0A0A0A0A0 DestinationFiles="@(_ReferenceScatterPaths->
 '$(_DeploymentApplicationDir)%(Filename)%(Extension)$(_DeploymentFileMappingExtension)')"
A0A0A0A0A0A0A0A0A0A0A0 SkipUnchangedFiles="true"/>
A0A0A0A0A0A0A0 <FormatUrl InputUrl="$(_DeploymentApplicationUrl)">
A0A0A0A0A0A0A0A0A0A0A0 <Output TaskParameter="OutputUrl" PropertyName="_DeploymentFormattedApplicationUrl"/>
A0A0A0A0A0A0A0 </FormatUrl>
A0A0A0A0A0A0A0 <FormatUrl InputUrl="$(_DeploymentComponentsUrl)">
A0A0A0A0A0A0A0A0A0A0A0 <Output TaskParameter="OutputUrl" PropertyName="_DeploymentFormattedComponentsUrl"/>
A0A0A0A0A0A0A0 </FormatUrl>
A0A0A0 </Target>

Finally you need include the new targets in your project, open your csproj file with a text editor and include the following line before the </Project> end tag.

A0 <Import Project="Customized.targets" />

The next time you publish the project you will see all assemblies and files inside the published directory.

5 Comments

  • THANK YOU!
    You're a freakin' genius! I've been trying to figure this out all day. We have a plug-in type architecture and we recently removed the references to the plug-in assemblies and I could not get them to publish. Now, one question if you don't mind. The plug-ins are/can be customer specific so I would like to put them into Groups so I can download on demand using the clickonce api. Can that be done using your technique?

    Thanks again,
    Greg

  • That is because some targets in .NET 3.5 and .NET 3.5 SP 1 changed, you should replace the parts that were part of the original target in Microsoft.Common.Targets.

  • When I publish it from VS 2008, it works fine and published in the right place.
    But when I tried to build it from commandline with /t:publish /p:Configuration=Release,for some reason, it published in the ..\bin\release folder.
    When I trid to run it, it gave me "Canot continue, The application is improperly formatted.
    Here is the detail:
    ERROR SUMMARY
    Below is a summary of the errors, details of these errors are listed later in the log.
    * Activation of C:\Fsa\Departments\FinancialProducts\Configurator\bin\Release\Configurator.application resulted in exception. Following failure messages were detected:
    + Exception reading manifest from file:///C:/Fsa/Departments/FinancialProducts/Configurator/bin/Release/Configurator.application: the manifest may not be valid or the file could not be opened.
    + Manifest XML signature is not valid.
    + No signature was present in the subject.
    Any idea? I have signed clickonce manifests certificate, but it still doesn't work
    BTW, it is a win form project.

  • This sample does not work for Visual Studio 2008 (Only for VS 2005). I will publish a sample for VS 2008 SP 1 in a few days.

  • The new version targeting VS 2008 is posted here http://weblogs.asp.net/marianor/archive/2009/05/01/publish-a-clickonce-deploy-with-assemblies-not-referenced-in-visual-studio-2008-sp1.aspx

Comments have been disabled for this content.