How do you include additional files using VS2010 web deployment packages?
Asked Answered
J

7

130

I am testing out using the new web packaging functionality in visual studio 2010 and came across a situation where I use a pre-build event to copy required .dll's into my bin folder that my app relies on for API calls. They cannot be included as a reference since they are not COM dlls that can be used with interop.

When I build my deployment package those files are excluded when I choose the option to only include the files required to run the app. Is there a way to configure the deployment settings to include these files? I have had no luck finding any good documentation on this.

Jape answered 30/4, 2010 at 19:23 Comment(0)
C
177

Great question. I just posted a very detailed blog entry about this at Web Deployment Tool (MSDeploy) : Build Package including extra files or excluding specific files.

Here is the synopsis. After including files, I show how to exclude files as well.

Including Extra Files

Including extra files into the package is a bit harder but still no bigee if you are comfortable with MSBuild, and if you are not then read this. In order to do this we need to hook into the part of the process that collects the files for packaging. The target we need to extend is called CopyAllFilesToSingleFolder. This target has a dependency property, PipelinePreDeployCopyAllFilesToOneFolderDependsOn, that we can tap into and inject our own target. So we will create a target named CustomCollectFiles and inject that into the process. We achieve this with the following (remember after the import statement).

<PropertyGroup>
  <CopyAllFilesToSingleFolderForPackageDependsOn>
    CustomCollectFiles;
    $(CopyAllFilesToSingleFolderForPackageDependsOn);
  </CopyAllFilesToSingleFolderForPackageDependsOn>

  <CopyAllFilesToSingleFolderForMsdeployDependsOn>
    CustomCollectFiles;
    $(CopyAllFilesToSingleFolderForMsdeployDependsOn);
  </CopyAllFilesToSingleFolderForMsdeployDependsOn>
</PropertyGroup>

This will add our target to the process, now we need to define the target itself. Let’s assume that you have a folder named Extra Files that sits 1 level above your web project. You want to include all of those files. Here is the CustomCollectFiles target and we discuss after that.

<Target Name="CustomCollectFiles">
  <ItemGroup>
    <_CustomFiles Include="..\Extra Files\**\*" />

    <FilesForPackagingFromProject  Include="%(_CustomFiles.Identity)">
      <DestinationRelativePath>Extra Files\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
    </FilesForPackagingFromProject>
  </ItemGroup>
</Target>

Here what I did was create the item _CustomFiles and in the Include attribute told it to pick up all the files in that folder and any folder underneath it. If by any chance you need to exclude something from that list, add an Exclude attribute to _CustomFiles.

Then I use this item to populate the FilesForPackagingFromProject item. This is the item that MSDeploy actually uses to add extra files. Also notice that I declared the metadata DestinationRelativePath value. This will determine the relative path that it will be placed in the package. I used the statement Extra Files%(RecursiveDir)%(Filename)%(Extension) here. What that is saying is to place it in the same relative location in the package as it is under the Extra Files folder.

Excluding files

If you open the project file of a web application created with VS 2010 towards the bottom of it you will find a line with.

<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />

BTW you can open the project file inside of VS. Right click on the project pick Unload Project. Then right click on the unloaded project and select Edit Project.

This statement will include all the targets and tasks that we need. Most of our customizations should be after that import, if you are not sure put if after! So if you have files to exclude there is an item name, ExcludeFromPackageFiles, that can be used to do so. For example let’s say that you have file named Sample.Debug.xml which included in your web application but you want that file to be excluded from the created packages. You can place the snippet below after that import statement.

<ItemGroup>
  <ExcludeFromPackageFiles Include="Sample.Debug.xml">
    <FromTarget>Project</FromTarget>
  </ExcludeFromPackageFiles>
</ItemGroup>

By declaring populating this item, the files will automatically be excluded. Note the usage of the FromTarget metadata here. I will not get into that here, but you should know to always specify that.

Carilla answered 1/5, 2010 at 3:15 Comment(19)
Could you extend your example in order to include additional project output into publish?Maddock
Is there any way to get diagnostic information about the files that are (or in my case, aren't) included by the target? I've asked this as a new question - stackoverflow.com/questions/11557915/debugging-msbuild-actionsCoalfish
@SayedIbrahimHashimi Can you use this technique to include two sets of files?Pants
I have VS2012 (RC) installed, and for me there was a different DependencyProperty. To support mixed teams (and our build server), I had the original CopyAllFilesToSingleFolderForPackageDependsOn configuration and a duplicate using the DependencyProperty CopyAllFilesToSingleFolderForMsdeployDependsOnToreutics
@SayedIbrahimHashimi regarding the update following VS2012 (RC), maybe there's a typo: the second block, the one related to MsDeploy, still references $(CopyAllFilesToSingleFolderForPackageDependsOn), which instead is related to Package. Shouldn't that change accordingly and reference MsDeploy as well ?Mange
(please, MsDeploy -> Msdeploy)Mange
This is wonderful. Using this to deploy some version information stored in a txt file.Proceleusmatic
This doesn't seem to work for me. I'm using VStudio 2013. :( Is the above msbuild setup work for 2013?Egomania
@SayedIbrahimHashimi and co. have created a much more up-to-date version of this guide on the asp.net website. I highly recommend that link, since that was the difference between me getting stuck modifying the csproj file instead of the pubxml file.Macrophage
Thanks for providing an answer that works, but is there any way to hook into Web Deploy packaging via a script? Don't mean to rant, but builds are highly custom and naturally procedural, and if using Web Deploy is going to require us to replace our packaging scripts with declarative XML...well...it's going to be a bit ugly and not very maintainable.Galileo
I modified the csproj file instead of the pubxml file as well. A simple note would have saved me some headache here (didn't read comments until it didn't work :P).Geostrophic
@SayedIbrahimHashimi, Does excluding files from deployment also excludes from msdeploy backups?Holley
@SayedIbrahimHashimi there seems to be a typo in this line of code: <CopyAllFilesToSingleFolderForMsdeployDependsOn> CustomCollectFiles; $(CopyAllFilesToSingleFolderForPackageDependsOn); </CopyAllFilesToSingleFolderForMsdeployDependsOn> I believe it should be: $(CopyAllFilesToSingleFolderForMsdeployDependsOn). Can you please confirm! Thanks. I have updated the answer btw.Gladisgladney
As was already stated, you should add the part about needing to make the changes to the .pubxml file in the 'Properties\PublishProfiles' solution folder, since when I first came across this, I was editing my project file, which is not the proper way anymore (at least not as of 2010/2012 I think). Looks at Adam's comment above for a reference link.Geostrophic
My files are copied to the package folder, but they are not copied to the deployment , any idea why ?Heracliteanism
@pacman it sounds like the Target copying files into the package directory is running after the package is created.Carilla
And if you want to exclude a file from the _CustomCollectionFiles you simply add an attribute: <_CustomFiles Include="..\Extra Files***" Exclude="..\ExtraFiles\Path\File1ToExclude.txt;..\ExtraFiles\Path\File2ToExclude.txt;"/>Bistort
Unfortunately, solution didn't help but being able to inspect cs.proj file by unloading project is very helpful. Thank youHailey
The inclusion example seems to be documented here: learn.microsoft.com/en-us/aspnet/web-forms/overview/deployment/…Danelle
F
22

A simpler solution is to edit the csproj file to include the required dll in the bin folder and then create a beforebuild target to copy the item into the bin folder from the common library folder where we store our 3rd party dlls. Because the item exists in the solution file it is deployed by msbuild/msdeploy and nothing complicated is needed.

Tag used to include file without adding through VS (which will want to add it to your VCS usually)

<Content Include="Bin\3rdPartyNative.dll" ><Visible>false</Visible></Content>

This is the BeforeBuild target that worked for me:

<Target Name="BeforeBuild">
    <Message Text="Copy $(SolutionDir)Library\3rdPartyNative.dll to '$(TargetDir)'3rdPartyNative.dll" Importance="high" />
    <Copy SourceFiles="$(SolutionDir)Library\3rdPartyNative.dll" DestinationFiles="$(TargetDir)3rdPartyNative.dll" />
</Target>

Edited to include @tuespetre's suggestion to hide the entry thus removing the previous downside of a visible bin folder. Unverified by me.

Filemon answered 16/4, 2011 at 5:49 Comment(7)
"simplicity is the ultimate sophistication"Sediment
This works in many cases, but does not work if you have files that need to be included outside of the bin folder.Faux
@Faux it's a copy, you can include it from anywhere you have permission to read and write from.Filemon
@toxaq, I could be missing something, but the problem I encountered was that I actually needed the files in a location in the deployment package that was not in the bin folder. So yes, you can copy the files from anywhere to the bin folder, but they won't be included in the right location in the deployment package in that scenario. For what its worth, the situation I ran into was with the ClearScript.V8 project - the native .dlls must not appear in the bin directory, but must appear in its parent - see clearscript.codeplex.com/discussions/438696 for the discussion.Faux
This was a long time ago but before build is before the deployment package is created, so if the file exists, it will be included exactly where you copied it to. You don't have to use targetdir but you will need an understanding of the esoteric way Microsoft decided to layout their build folders and consequently configure their deployment packages.Filemon
@Filemon - Add tuespetre comment to your answer, and it would be the simplest solution ever. Nice one.<Content Include="Bin\3rdPartyNative.dll"><Visible>false</Visible></Content>Cheltenham
@Cheltenham thanks, have made that edit. Don't have any MS stuff to test with so I've not verified it.Filemon
R
8

So Sayed's implementation did not work for me. I'm using VS2013 and using the Web Deploy package and needed to add some plugin DLLs from another folder into the bin of the deploy package. Here's how I managed to make it work (much easier):

At the bottom of your csproj file add:

<Target Name="AdditionalFilesForPackage" AfterTargets="CopyAllFilesToSingleFolderForMsdeploy">
    <ItemGroup> 
        <Files Include="..\SomeOtherProject\bin\$(Configuration)\*.*"/>
    </ItemGroup>
    <Copy SourceFiles="@(Files)" DestinationFolder="$(_PackageTempDir)\bin\" />  
</Target>

Other mentionables in the csproj file:

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
    <DeployOnBuild>true</DeployOnBuild>
    <DeployTarget>Package</DeployTarget>
    <DeployIisAppPath>Default Web Site/MyWebsite</DeployIisAppPath>
    <DesktopBuildPackageLocation>..\output\Service\Service\Service.Release.zip</DesktopBuildPackageLocation>
    <FilesToIncludeForPublish>OnlyFilesToRunTheApp</FilesToIncludeForPublish>
    <ExcludeGeneratedDebugSymbol>true</ExcludeGeneratedDebugSymbol>
    <PublishDatabases>false</PublishDatabases>
</PropertyGroup>

<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v12.0\WebApplications\Microsoft.WebApplication.targets" />
Rhodolite answered 8/4, 2015 at 0:12 Comment(1)
Thank you. I'm using VS2015 and I also needed to add DLLS from another project bin folder. Your solution was the easiest one and worked flawlessly.Mitchellmitchem
V
7

Just like @toxaq, but an even simpler solution is to:

In the solution explorer add the file as a link to the library/references folder, and then in the properties set it to be copied to output of the build.

Viscacha answered 15/5, 2011 at 3:13 Comment(1)
-1 this assumes that the project wishes to have an explicit linker-time relationship. Not suitable for plug-in type systemsBrandes
T
5

Wanted to comment to emphasize Emil Lerch's comment above. If you have installed an Azure SDK, then look for a different DependencyProperty.

Basically, you may need to use "CopyAllFilesToSingleFolderForMsdeployDependsOn instead of "CopyAllFilesToSingleFolderForPackageDependsOn". I'm not really an advanced MsBuild guy and I wasted hours pulling my hair out trying to determine why my targets were not getting called.

Here is another link if this does not work for you and you have installed an Azure SDK: http://forums.iis.net/t/1190714.aspx

Thuggee answered 17/11, 2012 at 3:43 Comment(0)
P
3

As an addendum to Sayed's answer, I found that a static declaration of ExcludeFromPackageFiles items within my project was not enough. I needed to exclude certain DLLs that were only available after compile (Azure specific Ninject modules that are not needed when I deploy to IIS).

So I tried to hook in generating my ExcludeFromPackageFiles list using the CopyAllFilesToSingleFolderForPackageDependsOn trick Sayed posted above. However, this is too late as the packaging process has already removed the ExcludeFromPackageFiles items. So, I used the same technique, but a little earlier:

<PropertyGroup>
    <ExcludeFilesFromPackageDependsOn>
        $(ExcludeFilesFromPackageDependsOn);
        _ExcludeAzureDlls
    </ExcludeFilesFromPackageDependsOn>
</PropertyGroup>

<Target Name="_ExcludeAzureDlls">
    <ItemGroup>
        <FilesForPackagingFromProjectWithNoAzure Include="@(FilesForPackagingFromProject)"
                               Exclude="%(RootDir)%(Directory)*Azure*.dll" />
        <AzureFiles Include="@(FilesForPackagingFromProject)"
                    Exclude="@(FilesForPackagingFromProjectWithNoAzure)" />
        <ExcludeFromPackageFiles Include="@(AzureFiles)">
            <FromTarget>_ExcludeAzureEnvironmentDlls</FromTarget>
        </ExcludeFromPackageFiles>
    </ItemGroup>
</Target>

Hope that helps someone...

Phthisic answered 12/5, 2011 at 12:57 Comment(0)
A
1

Also, it is possible to set the file as Content | Copy always

Also, it is possible to set the file as Content | Copy always

Amygdaline answered 24/10, 2019 at 7:48 Comment(2)
Seems this should be the top answer as it is the easiest and most obviousGondolier
But only if it's part of the project. This option is unavailable otherwise.Commendation

© 2022 - 2024 — McMap. All rights reserved.