views:

540

answers:

2

Are there good patterns for mapping solution configurations to environments and using MsDeploy for packaging per environment?

Shortest version: Grab this file, and try to change the .msbuild file so that a package is created.


Details

I have a solution with a large number of libraries and an ASP.NET MVC application. I drive the build with an msbuild file that calls the main solution and then does other things. I want to use the new msdeploy packaging to prepare a .zip file for later distribution, but I'm having various difficulties.

My solution has 4 configurations: Local, Dev, Test, and Prod, which match the environments I want to map to. In that solution, all of the libraries have Debug and Release modes like usual. For example, in Local solution mode, all libraries compile in Debug mode. Then, the main application has matching environments with the solution, so that I can have Web.Dev.config and so on, which seems like the natural way to use things.

If I package like this:

<Target Name="BuildWebPackage">
  <MSBuild Projects="..\Publisher\Site\Site.vbproj"
           Targets="Package"/>
</Target>

I get a problem where the Configuration=Local is incorrectly mapped down to the library projects that Site.vbproj references, and it can't compile them.


I see two possible solutions: one I can't get to work right, and the other is extremely ugly.

Attempt 1

I attempt to call the Package target via the solution (in this example, "Applications" is the solution folder that the Site project is in... I've simplified things down for this post because there are actually multiple applications in the solution.)

<Target Name="BuildWebPackage">
  <MSBuild Projects="..\Publisher\Publisher.sln"
           Targets="Applications\Site:Package"/>
</Target>

I think this SolutionFolder\ProjectName:Target syntax is how to do this, because :Clean runs... however, this throws

error MSB4057: The target "Applications\Site:Package" does not exist in the project.

Attempt 2

Now for the ugly solution: it works if I modify ALL my libraries to have 4 additional configurations for those 4 solution configurations. However, this is ugly and really a bad plan if I want to co-develop a shared library later with a project that has different environments. Also, those environments have nothing to do with the library and only make sense in the context of the top-level applications using the libraries. Tastes bad.


Huh?

I like having the multiple environments in the solution, and the fancy new Web.config replacement stuff, but I don't know how to call the msdeploy Package task in this situation so I can build the package in TeamCity.

(Note that I probably do NOT want to call the msdeploy command line, because that's used to turn an IIS app into a package. Not what I'm doing here.)


Sample

Again, I've been completely stumped here, so if you want to help experiment, I've put together this sample solution.

A: 

I've done something similar that may be useful. In a recent project, we had 'Dev', 'Test' and 'Prod' environments.

I added solution configurations for each of these.. eg.

  • Release-Dev
  • Release-Test
  • Release-Prod

For most projects in the solution, these configurations were just linked to the regular 'Release' build, but where appropriate, some projects did have distinct 'Release-Test' build configurations where there might be #if/#endif stuff in the code.

This would also make sense to allow customisation for your msdeploy config per configuration too.

Regarding the msbuild target. The target referrs to the name of a element. eg you could call msbuild with /t:BuildWebPackage for your example above.

David Gardiner
Yes, the target refers to an element. My problem isn't calling BuildWebPackage, it's *what* to call in the BuildWebPackage that will correctly use the new packaging goodies to build the package. In your example, if I make the web project have `Release-Test`, then I can call package on that .proj file BUT then msbuild tries to build all the other libraries also in `Release-Test`. If I try to build the sln, I don't know what msdeploy target to put in because "Package" is no longer available at the solution level.
Dan Fitch
Hmm.. so if you do want dependencies built then that sounds a reasonable thing to happen.Otherwise could you not just un-check the 'build' option for those projects in the solution configuration manager?Maybe I've misunderstood your question.
David Gardiner
The problem is that the solution knows to look for the library files in `Release`, but the proj file thinks it should be looking in `Release-Test` for those libraries, which doesn't exist, so it tries to build them, which doesn't work.I'm going to package up a simple example project and stick it somewhere.
Dan Fitch
Added sample to original post. http://dan.mindfill.com/tmp/SamplePackage.zip
Dan Fitch
+7  A: 

The first attempt failed because Package target doesn't exist in the solution file. When using MSBuild on a solution file, a temporary MSBuild project is created (SamplePackage.sln.metaproj); this project file contains only some targets (Build, Clean, Rebuild, Publish, ...)

Solution : DeployOnBuild & DeployTarget properties

One way to do what you want is to use DeployOnBuild property like this :

<PropertyGroup Condition="'$(Configuration)' == ''">
  <Platform>Any Cpu</Platform>
  <Configuration>Dev</Configuration>
  <PackageLocation>$(MSBuildProjectDirectory)\package.zip</PackageLocation>
</PropertyGroup>

<Target Name="Build">
  <MSBuild Projects="SamplePackage.sln"
           Targets="Build"/>
</Target>

<Target Name="BuildWebPackage">
  <MSBuild Projects="SamplePackage.sln"
           Properties="Platform=$(Platform);
                       Configuration=$(Configuration);
                       DeployOnBuild=true;
                       DeployTarget=Package;
                       PackageLocation=$(PackageLocation);"/>
</Target>
  • DeployOnBuild=true : deployment must be made when Build is called
  • DeployTarget=Package : for deployment creates a package
  • PackageLocation : indicates the filepath of the package file

Additional links :

madgnome
Awesome, thanks. This is indeed the answer.
Dan Fitch
HOURS spent on this...this is certainly not well documented anywhere. I applaud you fine sir.
Ryan Eastabrook