Update 20/06/12 – A working sample of the below can be found in my Nant.Builder nuget package.
Our team recently upgraded to the August 2011 Azure tools update, which provided some nice new features, but completely broke our automated build process. This was because the way Azure builds were created was modified (although in fairness it now seems to be more inline with Msdeploy builds). Fixing this was pretty painful, so I thought I’d blog it.
There are 2 steps to creating an Azure package:
- Use MSBuild to create a MSDeploy package with the appropriate configuration
- Use CSPack to use the MSDeploy package files to create the Azure package you’ll deploy to the cloud.
Compiling your solution for Azure using MSBuild on the command line
First we need is to build a MSDeploy package with the correct configuration. If you’re using web.config transforms (and you really should be) this also ensures that the web.config file is set with the correct transforms. So we want to execute MSBuild with the following parameters:
msbuild.exe YourSolution.sln /p:Configuration=Release /p:DeployOnBuild=true /p:DeployTarget=Package /p:AutoParameterizationWebConfigConnectionStrings=false
This will create a MSDeploy package. The AutoParameterizationWebConfigConnectionStrings flag is required if you’re using web.config transforms – because we’re not using MSDeploy to actually deploy our package we can’t rely on it to populate the connection string. If the value is set to true your connection string will look like this:
connectionString="$(ReplacableToken_HuzuSocialDB-Web.config Connection String_0)" />
Clearly this would fail once running on Azure. With the flag set to false, the connection string is transformed along with any other settings.
Using CSPack on the command line to create your Azure package
We now want to take the MSDeploy package files and turn them into a Azure package. First we need to find the MSDeploy package files – these should be located in the obj directory of your Web App. The location is set in the Package/Publish Web settings in the properties of your web project, however, I wouldn’t recommend changing the defaults:
If you navigate to the obj directory, you’ll want to then drill into the directory named after the Release-Configuration you supplied to MSBuild, eg:
The directory we are actually interested in is PackageTmp as this is what MSDeploy uses to create the package, but most importantly here you will find the transformed web.config file.
We can now point CSPack at the PackageTmp directory. The CSPack executable lives in the bin directory of Azure SDK
C:\Program Files\Windows Azure SDK\v1.4\bin
So to build our package we run CSPack with the following params
cspack.exe C:\HuzuSocial\HuzuSocial.Azure\ServiceDefinition.csdef /role:HuzuSocial.App;C:\HuzuSocial\HuzuSocial.App\obj\Release\Package\PackageTmp /rolePropertiesFile:HuzuSocial.App;.\AzureRoleProperties.txt" /sitePhysicalDirectories:HuzuSocial.App;Web;C:\HuzuSocial\HuzuSocial.App\obj\Release\Package\PackageTmp /out:C:\HuzuSocial\HuzuSocial.Azure\HuzuSocial-Azure-Release.cspkg
There’s a lot going on here, so I’ll break it down line by line
This tells CSPack where your ServiceDefinition file is located. Next:
This specifies where the files to create the role are located, in our case, this the PackageTmp directory that MSBuild created for us, as described above. Note that the role name, in this example HuzuSocial.App must match the WebRole name as specified in the ServiceDefinition file:
<WebRole name="HuzuSocial.App" vmsize="Small" >
This is optional if you’re working on .Net 3.5 but if you’re working with .Net4 you need to tell CSPack that you’re targetting framework v4. This is done by creating a txt file that you can then point CSPack at, in our example we have the file in the same directory as CSPack, but it you can store it anywhere (I actually have added it to our solution). The entry in the file is as follows:
Update 08/12/11 – As of SDK 1.6 you also need to specify EntryPoint parameter, especially if you’re working with Diagnostics. See this post for more details.
Here we are telling CSPack how the physical files are to be packaged for deployment to Azure. Here we are specifying the name of our role, our site name, as defined in the ServiceDefinition file, and finally where the files are located. (It is here I believe that we can define multiple sites to be hosted in one role). Finally we have:
This is the most straightforward param, simply telling CSPack where the package file should be output and what it should be called.
You should now be able to automate the above in your build tool of choice, I use NAnt. Meaning everytime someone on the team checks in we have a new Azure package ready for deployment. Next steps would be for the package to be deployed into a staging role automatically using CSRun, if I get round to this I’ll blog it as well.
We can also conclude that all of this is very non-obvious. Microsoft do not make it easy to do Continuous Integration (CI), especially with Azure packages. They have improved the tooling to deploy to Azure from your desktop, however, the whole point of CI is to ensure all your tests have passed, there’s no build errors etc. Deploying from your desktop circumvents all of these, not to mention introducing a human element into deployment that could break something. I feel MS really could help us out by making all the above a lot more straight-forward.
I couldn’t have created this post without the following invaluable info: