Most ASP.NET development shops have multiple projects, each with multiple developers working on them. Keeping track of these projects, and making sure they are available in a common location for review can be quite a chore. Recently, I set up a staging server for my company using CruiseControl.NET. This enables any developer, project manager, or other stakeholder to have access to the latest version of the site as it is being built. Because it is an automated process, there is no developer time required to generate and post updates to the central development staging server. This method is also useful for teams practicing Continuous Integration, but the main goal is to use easily available tools to create an automated staging server for ASP.NET web applications.
This post outlines the steps required to create an automated staging server using CruiseControl.NET. It also goes through several gotchas that can cause issues if you aren't prepared for them.
What is CruiseControl.NET?
CruiseControl.NET (CCNet) consists of a suite of applications, but at its core is the CruiseControl.NET Server which is an automated integration server. The Server automates the integration process by monitoring the team's source control repository directly. Every time a developer commits a new set of modifications, the server will automatically launch an integration build to validate the changes. When the build is complete, the server notifies the developer whether the changes that they committed integrated successfully or not.
-- From the CruiseControl.NET site
What is Continuous Integration?
The practice of continuous integration represents a fundamental shift in the process of building software. It takes integration, commonly an infrequent and painful exercise, and makes it a simple, core part of a developer's daily activities. Integrating continuously makes integration a part of the natural rhythm of coding, an integral part of the test-code-refactor cycle. Continuous integration is about progressing steadily forward by taking small steps. ... A successful integration is a measure of progress. It provides feedback that the new code runs correctly in the integration environment and successfully interoperates with the rest of the code base. Code sitting unintegrated in a developer's workspace simply does not exist. It is not part of the code base, it cannot be accessed by other developers or tested by the customer. Only when it has been successfully integrated is the benefit of the new code realised.
-- From the CruiseControl.NET site
Requirements
Server running IIS and ASP.NET 2.0 -- this will most likely be a normal Windows Server 2003 box, but a Windows XP box could be used if necessary. This should also work with Mono on a linux box or other platforms Mono supports, but I haven't tested that configuration.
CruiseControl.NET - Download [.zip]
MSBuild XML logger
Source control software - this example uses SourceGear Vault, but any other source control tool supported by CruiseControl.NET should work. Here's a list of the scc tools supported by CruiseControl.
Setting up CruiseControl
Setting up CruiseControl.NET is very simple.
- Grab the .zip.
- Extract it to a folder on your server.
- Create a virtual directory to the webdashboard folder.
Adding an application to CruiseControl
Create a folder to hold the root of your source repository. I generally put this in c:\dev, or some other simple folder on the server.
Use your source control to pull down the root folder of your application. This ensures that the folder structure is created properly. After adding the application to CruiseControl.NET, the source will be updated automatically.
Drop the MSBuild XML logger dll into the root folder of the application. Because the MSBuild task is a CruiseControl.NET addon, it doesn't include support for parsing the MSBuild build log.
Open the ccnet.config file in the server folder of the CruiseControl.NET application. I pulled out a template application configuration from my setup. Descriptions of each section follow.
<cruisecontrol>
<project name="project">
<webURL>http://server/project/</webURL>
<triggers>
<intervalTrigger seconds="60" />
</triggers>
<sourcecontrol type="vault" autoGetSource="true" applyLabel="false">
<executable>c:\program files\sourcegear\vault client\vault.exe</executable>
<username>user</username>
<password>password</password>
<host>source.company.com</host>
<repository>repository</repository>
<folder>$/project/trunk</folder>
<ssl>false</ssl>
<useWorkingDirectory>false</useWorkingDirectory>
<workingDirectory>c:\dev\project\trunk</workingDirectory>
</sourcecontrol>
<tasks>
<msbuild>
<executable>C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MSBuild.exe</executable>
<workingDirectory>c:\dev\project\trunk</workingDirectory>
<projectFile>project.sln</projectFile>
<buildArgs>/noconsolelogger /p:Configuration=Debug /v:diag</buildArgs>
<targets>Build</targets>
<timeout>15</timeout>
<logger>ThoughtWorks.CruiseControl.MsBuild.XmlLogger,ThoughtWorks.CruiseControl.MsBuild.dll</logger>
</msbuild>
</tasks>
</project>
</cruisecontrol>
This config file has only one project, but you can add additional projects by adding additional project sections. The important parts of this configuration are the webURL key (which we will use later in the dashboard page, so make sure this points to the location where you intend to set up the application virtual directory), and the configuration settings and locations for scc and the build task. The scc task points at a folder on the repository to bring down, and a location to put it in locally. Make sure this points properly to the application root directory you set up in the local dev tree by pulling the source manually. The projectFile key of the msbuild task should point to the solution file for the project. The workingDirectory key of the msbuild task points to the location locally where the solution file can be found.
For more information on the config file, check out the relevant section of the CruiseControl.NET documentation.
NOTE: If your app has binaries that are referenced in the projects, but included elsewhere in the source tree, you will have to create another task to pull the component binaries. You can do this by creating a seperate project section, but only including a scc task and not a build task. CruiseControl.NET does not require a build task in a project. This will pull the binaries as they are updated, eliminating another manual step.
<project name="Components">
<triggers>
<intervalTrigger seconds="60" />
</triggers>
<sourcecontrol type="vault" autoGetSource="true" applyLabel="false">
<executable>c:\program files\sourcegear\vault client\vault.exe</executable>
<username>user</username>
<password>password</password>
<host>source.company.com</host>
<repository>repository</repository>
<folder>$/Components</folder>
<ssl>false</ssl>
<useWorkingDirectory>false</useWorkingDirectory>
<workingDirectory>c:\dev\Components</workingDirectory>
</sourcecontrol>
</project>
NOTE: If the site you are using is an ASP.NET Web Application project, you will need to install the Web App Project support files on the server. You can get them from Microsoft here. If the server doesn't have VS 2005 installed, the installers will fail, but you can still get a web app project to build by copying over the msbuild support files manually. Follow these steps:
- On a development machine with VS and the web app project support files installed, go to C:\Program Files\MSBuild\Microsoft\VisualStudio\v8.0\WebApplications
- Get the Microsoft.WebApplication.targets file
- Create a C:\Program Files\MSBuild\Microsoft\VisualStudio\v8.0\WebApplications folder on your server
- Put the .targets file there
NOTE: If you are using an ASP.NET Web Site Project, and have dependancies, most likely they will not get copied properly during the compilation process. Here is an additional msbuild file you can add as a seperate task to copy the files over from the compiled web folder:
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<SourceDlls Include=".\PrecompiledWeb\client\bin\*.*" />
</ItemGroup>
<Target Name="Build">
<Copy sourcefiles="@(SourceDlls)" DestinationFolder=".\client\Bin" SkipUnchangedFiles="false" />
</Target>
</Project>
Call this with an additional msbuild task like so:
<msbuild>
<executable>C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\MSBuild.exe</executable>
<workingDirectory>C:\dev\project\client</workingDirectory>
<projectFile>copyassemblies.msbuild</projectFile>
<buildArgs>/noconsolelogger /p:Configuration=Debug /v:diag</buildArgs>
<targets>Build</targets>
<timeout>15</timeout>
<logger>ThoughtWorks.CruiseControl.MsBuild.XmlLogger,ThoughtWorks.CruiseControl.MsBuild.dll</logger>
</msbuild>
Building and checking status in CruiseControl
Run ccnet.exe. This will start a dos box that shows the CruiseControl.NET status as it parses the config file, pulls source from scc, and builds the application.
Open a browser and point it to the location where you installed the web console.
Unless you make pulling from scc and building directly a regular practice, you will probably run into some reference and other build issues. Most of these should be fairly simple to resolve, and by resolving these issues you increase the quality of your repository source tree.
Setting up the application virtual directory
Now that the application builds successfully, you can create a virtual directory in IIS to make it accessible.
Open IIS and create a virtual directory that points to the web application folder in the source tree. Use the same name you specified for the application url above.
Open a browser and navigate to the virtual directory you created. If all the build steps went properly and the application is configured directly, you'll see your app in all its automated build glory.
Setting up CruiseControl.NET as a service
Up till now, we've been running CruiseControl.NET as an interactive application. This is great for testing, but doesn't work so well in a production environment. Setting CruiseControl.NET up as a service is fairly straightforward. Here is a tutorial that will walk you through the process.
Creating a dashboard page
The final step is to create a dashboard page that pulls together all the applications you've set up and provides an easy way to navigate to them. This is a great page to hand to a non-techical person, manager etc., so they can easily keep track of application status and review or test applications at any time. I've created a sample page that pulls the app information from the ccnet.config file. Just drop the .aspx and web.config in a folder on the staging server. You'll need to change the ccnetConfigLocation appSettings key to point to the ccnet.config file, and the ccnetConsoleLocation to point to the web console url. Feel free to modify this as necessary to fit your organization. If you come up with any innovations, it'd be great to have them so I can merge them in so everyone can take advantage of them.
Files generated
- Sample dashboard page and web.config
- Sample ccnet.config
- copyassemblies.msbuild
Download