Publish a Clickonce deploy with assemblies not referenced in Visual Studio 2008 SP1

Some time ago I wrote a post about this subject, but that post only apply to Visual Studio 2005. The targets used in that post where changed. Basically this post is an update to Visual Studio 2008 SP1. Note that this post does not apply to Visual Studio 2008 without SP1, there were some changes between the two versions of the used target.

In this version we need replace only one target which is _DeploymentComputeClickOnceManifestInfo. This target is executed before the beginning of the publishing. You will need copy this target to a file, for example AssembliesCopy.targets, and add the logic to get the not referenced assemblies from the Modules folder. Take a look to the following target:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<Target

  Name="_DeploymentComputeClickOnceManifestInfo"

  Condition="'$(GenerateClickOnceManifests)'=='true'"

  DependsOnTargets="_DeploymentGenerateTrustInfo">

 

  <!-- Grab just the serialization assemblies for a referenced assembly.  There may also be a symbols file in ReferenceRelatedPaths -->

  <ItemGroup>

   <_SGenDllsRelatedToCurrentDll

    Include="@(_ReferenceSerializationAssemblyPaths->'%(FullPath)')"

    Condition="'%(Extension)' == '.dll'"/>

   <_SGenDllsRelatedToCurrentDll

    Include="@(SerializationAssembly->'%(FullPath)')"

    Condition="'%(Extension)' == '.dll'"/>

  </ItemGroup>

 

  <!-- Flag primary dependencies-certain warnings emitted during application manifest generation apply only to them. -->

  <ItemGroup>

   <_DeploymentReferencePaths Include="@(ReferencePath)">

    <IsPrimary>true</IsPrimary>

   </_DeploymentReferencePaths>

  </ItemGroup>

 

  <!-- Create list of items for manifest generation -->

  <ResolveManifestFiles

   TargetFrameworkVersion="$(TargetFrameworkVersion)"

   SigningManifests="$(SignManifests)"

   EntryPoint="@(_DeploymentManifestEntryPoint)"

   ExtraFiles="@(_DebugSymbolsIntermediatePath);$(IntermediateOutputPath)$(TargetName).xml;@(_ReferenceRelatedPaths)"

   Files="@(ContentWithTargetPath);@(_DeploymentManifestIconFile);@(AppConfigWithTargetPath)"

   ManagedAssemblies="@(_DeploymentReferencePaths);@(ReferenceDependencyPaths);@(_SGenDllsRelatedToCurrentDll);@(SerializationAssembly)"

   NativeAssemblies="@(NativeReferenceFile);@(_DeploymentNativePrerequisite)"

   PublishFiles="@(PublishFile)"

   SatelliteAssemblies="@(IntermediateSatelliteAssembliesWithTargetPath);@(ReferenceSatellitePaths)"

   TargetCulture="$(TargetCulture)">

   <Output TaskParameter="OutputAssemblies" ItemName="_DeploymentManifestDependencies"/>

   <Output TaskParameter="OutputFiles" ItemName="_DeploymentManifestFiles"/>

   <Output TaskParameter="OutputEntryPoint" ItemName="_DeploymentResolvedManifestEntryPoint"/>

  </ResolveManifestFiles>

 

  <!-- Begin custom fragments - Generate all managed assemblies inside modules -->

  <CreateItem Include="$(OutputPath)Modules\**\*.dll">

   <Output TaskParameter="Include" ItemName="ManagedAssemblies" />

  </CreateItem>

  <CreateItem

   Include="@(ManagedAssemblies)"

   AdditionalMetadata="TargetPath=Modules\%(RecursiveDir)%(Filename)%(Extension);DependencyType=Install;">

   <Output ItemName="_DeploymentManifestDependencies" TaskParameter="Include" />

  </CreateItem>

  <!-- End custom fragments -->

 

  <PropertyGroup>

   <_DeploymentManifestType>ClickOnce</_DeploymentManifestType>

  </PropertyGroup>

 

  <!-- Obtain manifest version from ApplicationVersion and ApplicationRevision properties -->

  <FormatVersion Version="$(ApplicationVersion)" Revision="$(ApplicationRevision)">

   <Output TaskParameter="OutputVersion" PropertyName="_DeploymentManifestVersion"/>

  </FormatVersion>

  <FormatUrl InputUrl="$(_DeploymentUrl)">

   <Output TaskParameter="OutputUrl" PropertyName="_DeploymentFormattedDeploymentUrl"/>

  </FormatUrl>

  <FormatUrl InputUrl="$(SupportUrl)">

   <Output TaskParameter="OutputUrl" PropertyName="_DeploymentFormattedSupportUrl"/>

  </FormatUrl>

  <FormatUrl InputUrl="$(ErrorReportUrl)">

   <Output TaskParameter="OutputUrl" PropertyName="_DeploymentFormattedErrorReportUrl"/>

  </FormatUrl>

</Target>

</Project>

Note that most of the lines came from the original target delivered from Microsoft; the lines added are in Italic.

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

<Import Project="AssembliesCopy.targets" />

After that, when you publish the project again the assemblies from the folder Modules will be copied in your Published folder.

You can download a sample project here.

4 Comments

  • Great article, the only problem is after everything is done, I publish the application and the installer gives an error going in. "Cannot continue. The application is improperly formatted. Contact the application vendor for assistance."

    Any idea why?

    Thanks.

  • You can check that your Modules folder is copied to your output folder. I mean that if you are compiling in Debug your Modules folder should be located in bin\Debug\Modules.
    Also be sure that the import of AssembliesCopy.target be the last import.

  • You have to check that all files were situated in the corresponding directory with the deploy extension. The same files should be in the manifest file. I put a sample project, you can download it.

  • I'm having problems during build on generating manifest if the folder to be copied has unmanaged dlls (Problem generating manifest. Could not load file or assembly 'path to x.dll' or one of its dependencies. An attempt was made to load a program with an incorrect format). Have you got an idea how to solve this issue?

Comments have been disabled for this content.