Thursday, September 17, 2009

Web Deployment Project Enhancements

[Note: This is a republish of a blog I wrote 2/8/2006 on a old blog]

Deploying a web project has always required some external software and sometimes manual changes/copying/etc. Thankfully, Microsoft has seen fit to help us with our web deployment scenarios and has created an add-on to Visual Studio 2005 called Web Deployment Project. If you are not familiar with the product, I would suggest you check it out as the rest of this article assumes you have it installed and are trying to use it for your builds. In attempting to use this add-on I ran across a few shortcomings in what I needed. Here are my workarounds.

Web.config Merging Enhancement

One of the nice things I was looking forward to was web.config file merging. Turns out this feature will not replace any section (due to bugs or shortcomings or something) and it makes you create a separate file for every section you want to merge. If you want to merge 5 sections and then you have a staging and release build, that’s 10 files you have to maintain (and will show up in your website in development and deployment).

A better solution is to extend the MSBuild rules of Web Deployment Project. What we want is one web.config file for each release we are doing and at build time the correct build file would be copied to web.config in the deployment folder. To accomplish this, create your build configurations and configuration files called *.[buildConfiguration].

As an example, let's say you have 2 deployment environments - Staging and Release. You will create two build configurations in VS, one called ‘release’ and one called ‘staging’. Now, create web.config.staging and a web.config.release. The changes below will cause the appropriate web.config.xxxx to be copied over web.config in the deployment folder depending on which build you do. Note this will work for ANY file, configuration files, graphics, anything, as long as the file name ends in the configuration name!

1) Right click the deployment project and choose 'Open Project File'. This will open the MSBuild file into the IDE.

2) At the bottom of the file you will see a commented section where it talks about how to extend this file using pre-built Targets. Add the following code:


<ItemGroup>

<!--list of all files that we are going to copy into the current config files.

So, for example, if we are on a release build, it will get all files called *.release-->

<MySourceConfigFiles Include="$(SourceWebPhysicalPath)\*.$(Configuration)" />

</ItemGroup>



<Target Name="AfterBuild">

<Copy SourceFiles="@(MySourceConfigFiles)" DestinationFiles="@(MySourceConfigFiles->'$(OutputPath)\%(Filename)')" />

</Target>
Note: The above only looks in the root of the web folder. If you need it to look in all folders you would need to modify it to build and copy a recursive list of files. See http://msdn2.microsoft.com/en-us/library/ms171454.aspx for more information


Too many files deployed

Another issue is all files from your project are copied to the deployment folder. You could of course exclude them from your project, but if you do that causes other problems. For example, in the enhancement above, if you do not copy them to the deployment folder, they are not available to copy because web deployment project uses a temporary folder for the build (since it modifies aspx files and such). So, to prevent this, you can add more MSBuild commands. Working off the example above, once the web.config is replaced with the correct version; we no longer need the other versions. To delete add the following:


<ItemGroup>

<!--list of all files that we can delete from the deployment folder-->

<MyUnNeededDestFiles Include="$(SourceWebPhysicalPath)\*.staging;$(SourceWebPhysicalPath)\*.release" />

</ItemGroup>



<Target Name="AfterBuild">

<Delete Files="@(MyUnNeededDestFiles->'$(OutputPath)\%(Filename)%(Extension)')" />

</Target>

Not Enough files deployed

I know I just wrote about too many files being deployed, but believe it or not, not enough files are copied and it happens at the same time! What happens is that any assembly you reference in your project that is in the GAC is not copied to the bin folder of your web application. Since it is not copied there, the web deployment project does not know you need it. Another example, is for some reason license files are not copied either, which you will need to run in the deployment environment! The best solution would be to parse the web.config file looking through the section, then use the GAC to locate the assembly and copy it for you. A much simpler solution is to just put what additional files you want to copy in the MSBuild file:


<PropertyGroup>

<InfragisticsFolder>c:\program files\Infragistics\NetAdvantage 2005 Volume 3 CLR 2.0\ASP.NET\bin</InfragisticsFolder>

</PropertyGroup>



<ItemGroup>

<!--Files registered in the GAC are not copied to the bin folder. List them all here so they will be!-->

<MyGACFiles Include="$(InfragisticsFolder)\Infragistics2.WebUI.Shared.v5.3.dll;

$(InfragisticsFolder)\Infragistics2.WebUI.UltraWebGrid.v5.3.dll;

$(InfragisticsFolder)\Infragistics2.WebUI.UltraWebNavigator.v5.3.dll" />

</ItemGroup>



<Target Name="AfterBuild">

<Copy SourceFiles="@(MyGACFiles)" DestinationFiles="@(MyGACFiles->'$(OutputPath)\bin\%(Filename)%(Extension)')" />

</Target>

If you want to do more than one of the suggestions above, you can combine the items together. Just be careful of the order – you don’t want to try to copy your config files after you have deleted them!

Let me know if you have any other ideas!

1 comment:

Charles said...

Thx for that quick bit about the deploy project.

Now, how do I get rid of the warnings because the build file gets validated against a schema that knows nothing about your "MySourceConfigFiles" element.

Thx -CTH