Publish a Visual Studio Cloud Project the Way You Want

I used to play with makefiles many years ago when I was developing on Unix systems, but I should admit I have not given it a go with the MSBuild files so far.

While we were building the Cloud Ninja project, deploying first version was easy, because there were no users of it yet, we have not released so using the production URL at www.thecloudninja.com did not generate any issues. Green field, no users yet, so continue publishing to there, yes? Easy…

Now we are working on the 2nd version of it, and we have people using the deployed version for their demos etc., we need to put together a scheme to get it running in multiple places:

  1. Production, regular updates every two weeks, publish to staging, do a VIP swap
  2. Test, a replica of the production version (with separate SQL Azure server, and Azure storage, plus a web and worker role. Reuse the existing STS and the Task application, unless there is a need to change them). We decided to publish to the production slot there, so we can have a fixed URL for it.
  3. Development, use local resources only, including a local SQL Express database, and development storage.

We will start pushing out regular updates in the coming weeks, so you should be able to see the changes I am mentioning here in CloudNinja.Cloud project.

In order to configure the different environments as pictured above, we needed to tweak the Cloud project’s project file. Alex Lambert has a great post in his blog describing how this can be done.

I will try to explain the steps we took to massage the MSBuild file to get it do what we want.

Basically, what we want to do, is to get the Visual Studio generate the service configuration files (*.cscfg) configured with different settings, such as different database connection strings, certificate thumb prints etc.

To explain it a little bit more, we want to have the default F5, debug behavior start using our local database server, and the local development fabric. On the other hand, right click, and selecting “Publish” on the CloudNinja.Cloud project, should package the solution, along with the service definition file (ServiceDefinition.csdef) and generate and push the appropriate service configuration file (cscfg) with the right settings for the test environment production slot. And for the production environment, we want things a little bit more controlled, thus we will take a manual approach here, and upload the appropriate cscfg file along with the generated package to the staging slot and do a VIP swap to bring it to the production slot to minimize the downtime. We decide to stop at the VIP swap technique, as we really do not need an uptime with higher SLA since this is a sample.

As demonstrated by Alex Lambert in his blog post, we used the Web project transformations, but also extended it to modify the the publish behavior. I am not going to explain the transformation techniques that are mentioned in that blog post here, so I will dive straight into what we have contributed. In order to get the publish action doing what we want, we needed to add two more steps to the process, namely

  1. Reconfigure the MSBuild items used by the “CorePublish” target
  2. Copy right files back after publish target is completed

Basic idea here is to specify transformation rules in ServiceConfiguration.Test and ServiceConfiguration.Staging files to transform ServiceConfiguration.cscfg base file, which targets the local debug environment.

The CorePublish target in the cloud targets file at

C:\Program Files (x86)\MSBuild\Microsoft\Cloud Service\1.0\Visual Studio 10.0

specifies the following actions:

  1. Create the publish directory
  2. Package the solution, using cspack utility (encapsulated within the custom tasks at the same directory as the custom targets file is), with the service definition file as defined with ServiceDefinitionCopy item
  3. Copy the file as defined by the item ServiceConfigurationCopy to  the publish location as the created directory above
  4. And deletes if there are any diagnostics files that are created

So, to get it working as we like it for the publish action, we needed to override the “CopyServiceDefinitionAndConfiguration” target defined in the Cloud Extensions include file that defines the ServiceConfigurationCopy  item. The reason we are overriding this is to modify the copy behavior, such that the original configuration file, which contains the development configuration settings get copied over to the Debug folder, whereas, the transformed test and staging configurations get coped to the Publish directory. So here is how it works:

  1. Remove the original ServiceConfigurationCopy item definition
  2. Redefine it with the Test definition (because this is what we want to publish to the test environment production slot)
  3. Copy both of those files appropriately
  4. And just let CorePublish task do its job to publish the Test configuration file to the Azure environment

Here is how this part looks:

Code Snippet
  1. <!– Overrride the original CopyServiceDefinitionAndConfiguration target –>
  2. <TargetName=CopyServiceDefinitionAndConfiguration>
  3.  
  4.     <MessageText=CloudNinja: Running CopyServiceDefinitionAndConfiguration target />
  5.  
  6.     <!– now redifine them to our liking–>
  7.     <ItemGroup>
  8.         <ServiceConfigurationCopyRemove=@(ServiceConfiguration->’$(OutDir)%(Filename)%(Extension)’) />
  9.  
  10.         <ServiceConfigurationCopyInclude=ServiceConfiguration.Test.transformedtobepublished.cscfg />
  11.  
  12.     </ItemGroup>
  13.  
  14.     <!– Create a copy of service configuration –>
  15.     <MessageText=Copying the service configuration. />
  16.     <Copy
  17.         SourceFiles=ServiceConfiguration.Test.transformed.cscfg
  18.         DestinationFiles=@(ServiceConfigurationCopy) >
  19.         <OutputTaskParameter=CopiedFilesItemName=FileWrites />
  20.     </Copy>
  21.  
  22.     <Copy
  23.         SourceFiles=@(ServiceConfiguration)
  24.         DestinationFiles=$(OutDir)ServiceConfiguration.cscfg>
  25.         <OutputTaskParameter=CopiedFilesItemName=FileWrites />
  26.     </Copy>
  27.  
  28.     <!– Create a copy of service definition –>
  29.     <MessageText=Copying the service definition. />
  30.     <Copy
  31.         SourceFiles=@(ServiceDefinition)
  32.         DestinationFiles=@(ServiceDefinitionCopy) />
  33.  
  34. </Target>

The second step we need to include is to get all of the transformed configuration files to the publish directory. We achieve this with adding a new target that runs after the AfterPackageComputeService target. Here is how it looks:

Code Snippet
  1. <TargetName=CopyTransformedEnvironmentConfigurationXmlAfterTargets=AfterPackageComputeService>
  2.       <CopySourceFiles=@(EnvironmentConfiguration->’%(Identity).transformed.cscfg’)DestinationFolder=$(OutDir)Publish />
  3.     <CopySourceFiles=ServiceConfiguration.Test.transformedtobepublished.cscfgDestinationFiles=$(OutDir)Publish\ServiceConfiguration.cscfg/>    
  4. </Target>

Remember, this whole post is all about how to set “CloudNinja.Cloud” as the startup project for your debug session, and selecting right click->publish to get it published to test, production slot.

It has got nothing to do with the STS or Task app configurations, we assume they will change very rarely, and did not make any configuration changes to them.

On important side note is you will notice a number of Message tasks in the MSBuild file. You will naturally expect to see some messages displayed in the output window of the Visual Studio, but, alas! no, nothing. Well, you need to go to Tools-Options on Visual Studio to control the verbosity level of the MSBuild messages here:

As always, happy coding, and have lots of fun doing it!

Leave a Reply