Tuesday, February 24, 2009

Web Packaging: Creating web packages using MSBuild

 

This post is next in the series of VS 2010 articles that we have been putting together to dive into the Web Deployment improvements with VS 2010 and IIS.  I would recommend reading the the preceding posts to get an overview of all the scenarios supported:

In this post I will cover web package creation using MSBuild command line.  Many medium to large sized teams plan on automating their build process for various good reasons like predictability for QA team, time saving as compared to on-demand manual build, early bug detection with Build Verification Tests (BVTs), knowing the current state of project integration, etc… Many argue that setting up the build system is not worth the trouble for a small project running only a few months; I would suggest otherwise, believe me setting up an automated build process once will pay you back   enough just within a few weeks and will get you into a mode where in the future doing this will be so much more easier… 

Anyways, if you choose to automate your build process there are various tools and technologies available out there, some of the popular ones are:

You can certainly take your build automation process to its best by using Continuous Integration model which we will discuss in subsequent posts.

In anycase, the entire Web Deployment story in VS 2010 uses MSBuild behind the scene which means that all the UI features in Visual Studio are actually wrappers over the underlying MSBuild Targets, Tasks and Properties.  In the previous post we talked about “Creating a Web Package using VS 2010” where we discussed setting up the Package properties in “Package Tab” of the project’s property pages as shown below:

All the properties that you set up in this UI are stored in your .vbproj or .csproj file.  We also talked about this tab being “Configuration” aware, which means that you can set different properties per build environment like Debug, Testing, Staging, Release/Production etc and all of these properties will be saved in your project file.

Now if you would like to create a web package using MSBuild it is much more simpler than you can imagine:

All you have to do is open  command prompt which has MSBuild path preset (e.g. Visual Studio Command Prompt which is available under Visual Studio 2010 –> Visual Studio Tools) and type the below command:

MSBuild "YourFullyQualifiedProjectName.csproj/vbproj" /T:Package

/T:Package is the MSBuild Target named Package which we have defined as part of implementation of the Web Packaging infrastructgure.

Interestingly, when you do not specify any MSBuild target, then for most projects “Build” is the default target hence just providing below command line simply builds your project

MSBuild “YourProject.csproj”

Also note that there can be various dependencies set between targets and our “Package” target has an explicit dependency on “Build” target which means that if the “Build” was not successful then “Packaging” will not even begin, this ensures that during your automated packaging you do not land up spending resources on creating faulty web packages.

By default MSBuild uses the “Debug” configuration but if you would like to create a package for your Staging configuration all you would have to do is:

MSBuild "ProjectName.csproj/vbproj" /T:Package /P:Configuration=Staging

/P:Configuration represents the Property named Configuration which you are setting to Staging…

Diving a tiny bit deeper - If you open your project file in a text editor then you should be able to see all the properties which we talked about from UI perspective in our previous post “Creating a Web Package using VS 2010”…  All these properties will not be visible in the project file until their default values are modified (just a tiny optimization to keep the files smaller and agile :-)). These same properties are optionally settable from command line as well...  Also there are certain properties which are not manifested in the UI or in the project file by default, but are still available behind the scene to provide extensibility and fine grain control that many expect, we will go into the details of those properties in later posts as well.

Anyways, most of the time you should be able to set most of your properties in the UI and use them without much modification in the command line scenario, although it is conceivable that some of the properties may require frequent modification during automated builds e.g. “Package Location”.  Below is a sample command of how you will set up the PackageLocation property along with the Configuration property:

MSBuild "MyProjectName.csproj" /T:Package /P:Configuration=Staging;PackageLocation="D:\Vishal\Package.zip"

When I run the above command then my package for “Staging” configuration will be created in “D:\Vishal\Package.zip”

It is important to note that items passed via command line override the values set in the project file, this ensures that most common values of the properties can be stored in the project file and eventually shared by the entire team…  The ones which need to be momentarily overridden during build time can be set from the command line. 

Also it is good to remember that if you like to pass more than one property to MSBuild command then you can do so by separating multiple properties by semicolon ; as shown above for Configuration and PackageLocation.

The above command line examples can very easily be plugged into automated build systems like CC.Net, TFS, etc, we will look into the process of setting some of these environments in later posts as well.

For now, I hope you will be able to envision the prospects of creating these Web Packages in an automated fashion and share them across your teams on regular basis.

20 comments:

Ryan & Teena said...

Enjoyed your post. Couple of questions. Are there any barriers to doing this w/ a vs2008 setup? We currently user .msbuid/.wdproj with many assemblies and targets leading to a aspnet precompiles for deployments. I've been looking for a same of how try and combind the precompile and msdeploy task/activities.

Vishal R Joshi said...

There have been a few asks around using these feature sets in VS 2008... Well in all honesty it is just set of target files and task dlls in MSBuild directories, if you could copy them then it could work... Ofcourse it is a non supported scenario :-)
There is also one more big gotcha that the task dlls are written using .NET 4.0 so without .NET 4.0 things will not work...
I would say there will be a convoluted way by which someone can make it work in VS2008 but unfortunately not supported...
Hope this helps...
-Vishal

PS: I am predicting that plugging pre-compile & merge into VS10 would be much more simpler...:-)

David Keaveny said...

How is this supposed to work in a TeamBuild environment? Everything I've seen seems to be based on the concept that deployments are going to be done from Visual Studio - you choose a configuration, build, and deploy. But what happens if you use continuous integration, and then the built packages are handed over to your operations team for deployment? Do you have to create individual packages for each configuration in your build?

TS said...

Hi Vishal,

I am following your series on Web Deployment with VS 2010. In the previous post in this series, •Web Deployment with VS 2010 and IIS" http://vishaljoshi.blogspot.com/2009/02/web-packaging-creating-web-package.html, you said that VS 2010 uses MSDeploy to create the Web Package.

In this post, you show how to use MSBuild tool to build a Web Package. There are somethings i dont understand and i have a few questions.

But which tool actually creates the web package ? Can both be used for this ? What is the co-relation between MSBuild and MSDeploy? Is MSDeploy an MSBuild task ?

I'd appreciate any respone :)

Will said...

Vishal, I know it's a year after you wrote this thread, but can you point me to any information about how to do the '1-click publish' from the command line?

I just cannot find this - I found another post comment where you suggested to someone that adding True to a project would force VS to use msdeploy to to the publishing, and hence reveal the magic command line, but I'm unable to make this work with VS2010RC, though I might be adding it to the wrong part of the project.

I can do packaging with msbuild no problem, but not publishing.

Justin Wignall said...

Vishal, your write ups are fantastic and have helped no end.

I have got to the point where I can create a package such as:

MSBuild "MyProjectName.csproj" /T:Package

However I would ideally like to do this with TFS. I have edited the build definition and added

/T:Package

to the MSBuild Arguments option but get the errors

"The target "Package" does not exist in the project."

and

TF270015: 'MSBuild.exe' returned an unexpected exit code. Expected '0'; actual '1'.

I had assumed they were using the same MSBuild underneath so have I missed some important step?

Any help would be massively appreciated, once again thanks for your great effort in these tutorials and hiints.

zvolkov said...

Note that you can have packaging done during solution build. For that, set DeployOnBuild=true and DeployTarget=Package. For more info see this blog post: http://zvolkov.com/blog/post/2010/05/18/How-to-Publish-Web-Site-project-using-VS2010-and-MsBuild.aspx

Ed. said...

Nice article. Did you ever post a follow-up on integration with cc.net? I'd like to automate creating deployment packages for each of our environments (iTest, Staging, and Production). Thanks.

Vishal R Joshi said...

>> CC.NET
Hi Ed
Unfortunately, I did not post a CC.Net blog post, it is in the queue to be written, although someone from our team is hoping to take it up and provide a blog post soon..
In anycase the command line for calling packaging is "msbuild myproj.csproj /t:Package" which can be hooked into CC.Net easily so please do start with that and write back if you encounter any issues...
Thx
Vishal

Anonymous said...

Vishal, your write ups are fantastic and have helped no end.

I have got to the point where I can create a package such as:

MSBuild "MyProjectName.csproj" /T:Package

However I would ideally like to do this with TFS. I have edited the build definition and added

/T:Package

to the MSBuild Arguments option but get the errors

"The target "Package" does not exist in the project."

and

TF270015: 'MSBuild.exe' returned an unexpected exit code. Expected '0'; actual '1'.

I had assumed they were using the same MSBuild underneath so have I missed some important step?

Any help would be massively appreciated, once again thanks for your great effort in these tutorials and hints.

Vishal R Joshi said...

Hi there,
Regarding your question on why /t:Package does not work. I think this might be due to the fact that you are doing solution build and when you do so it will try to pass the Package target to all your projects. If you have things like classlibrary, winform etc part of the solution then it is likely that you will get the failure as these projects do not support the Package target. For that reason you might actually want to pass /p:DeployOnBuild=True. This will pass the property to every project and based on typical MsBuild semantics the projects who does not honor the property will ignore it (msbuild cannot do so for targets).
I hope this helps. I also have a blog post http://vishaljoshi.blogspot.com/2010/11/team-build-web-deployment-web-deploy-vs.html which talks about team build and deployment in detail.
hope this helps.
Thx
Vishal

jacderida said...

Hi Vishal,

Good post! I got my package to build just fine using a script in my local development environment, but then when I tried to run it on my build server I got the following error:
"D:\AgentWork\d055e5f687a62e1c\src\Saturn.WebUI\Saturn.WebUI.csproj : error MSB4057: The target "Package" does not exist in the project."

The build server also has web deploy installed on it. There is a version mismatch though - the development machine is running msdeploy 7.1.618.0 and the build server is running 7.1.1070.1. Note also that the build server doesn't have Visual Studio on it - but I wouldn't have thought that that would be a requirement for making the Package target available. Also, I'm using the .NET 4 version of msbuild on both machines.

Can you advise if there is an incompatibility between these 2 versions? Or do you need a visual studio install to have the package target available?

Many thanks,

Chris

Vishal R Joshi said...

Hi Chris,
Yes unfortunately it is required to install Visual Studio on the build server to enable the scenario. If you do not want to install full VS then you can also install VWD Express 2010.
Thx
Vishal

jacderida said...

Ahh ok, thanks for the information!

Unfortunately having a studio install on our build agents isn't an option for us, but at least I know :).

Cheers,

Chris

Anonymous said...

I think you can copy the tasks and targets located at C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v10.0 to your build machine at the same location. Then TFS works fine. Ofcourse this is not official but works for us.

Anonymous said...

Can you do anything to make the package creation as part of the build process in visual studio? For instance, when I build my web service, it also builds and generates the package?

Vishal R Joshi said...

Yes you can set DeployOnBuild property to true by manually editing the project file. Hopefully that will solve the problem.
Thanks
Vishal

Anonymous said...

How do I set application pool and possibly other properties when creating the package? Or at least how do I tell msbuild to use my custom parameters file when packaging the web application?

Vishal R Joshi said...

Hi Anonymous,
You just have to configure your local IIS settings to be what you want on remote. Once you do that then in Package/Publish settings you can just check the box which says "Include IIS Settings" and the package will automatically contain everything that you need.
thx
Vishal

Chikutoji said...

Nice post! I found it while trying to do the same thing using build server.

As a follow up, is there a way to set the application pool to an existing one in the target server? This is without using IIS settings on my web project.