Not too long ago, we moved our repository to www.visualstudio.com.
Some reasons behind the moves were:
- Visual Studio online repository is free for up to 5 developers (which suit our small team).
- We want to take advantage of the continuous delivery workflow that Azure and VS online offer.
- VS online has a nice Scrum portal that include feature, backlog and task management, drag-able Kanban board, burn down chart and cumulative flow diagram. The “virtual” project chat room is nice but we use Skype mostly to communicate with our remote team.
Since then, we’ve been working toward enabling continuous deployment on our Azure solution similar to what is described in this article: Continuous delivery to Azure using Visual Studio Online.
The purpose of this post is not to teach you how to do this. For that, please follow the steps described in the linked article above. What I wish to talk about here is more about what’s missing from the “happy day” scenario of doing continuous delivery as described in that article.
Azure Continuous Deployment of Visual Studio solution with multiple cloud service projects from Visual Studio Online
Caveat: I am an the accidental build master who does not have in depth knowledge of VS Build Process Template customization, not yet anyhow, so the solution described here might not be the most technically correct, but it works for us. If you know a better way to do this, by all mean, please share.
Originally, our Visual Studio solution contains multiple cloud service projects which we found to not work with the normal continuous deployment scenario that comes out of the box with Visual Studio Online and Azure.
Why out of the box build process will not work with Visual Studio solutions with multiple cloud service projects
Apparently, the standard continuous deployment workflow that comes out of the box prefers a solution with only a single cloud service project. You can see this in the build definition in the following section: Process/6.Deployment/Deployment/Windows Azure Deployment Environment. Basically, you can only deploy a single cloud service if you doing it the standard way. You might be able to tweak the build definition workflow but we decided to not waste too much time researching this.
Move each cloud service project into their own Visual Studio solutions
So, we moved the extra cloud service projects from our main Visual Studio solution into their own Visual Studio solutions and re-establish any project / binary references as necessary. This, however, present a different challenge when doing .NET Azure SDK upgrade, which I will talk about in a different post. Each of these solutions are then associated with their own continuous delivery build definitions. We found this setup to be working quite nicely.
Original VS solution:
My Awesome VS Solution
- Cloud Service Project 1 (i.e. main web + worker role that will always need to be deployed as pair)
- Cloud Service Project 2 (i.e. incoming email handler worker role, unfrequently deployed)
- Supporting library project 1 (i.e. Azure specific library)
- Supporting library project 2 (i.e. SQL Data Access library)
- Actual web project
- Worker role project
- Email worker project
Refactored VS solutions:
Main Web + Worker Role VS solution
- Cloud Service Project 1 (main web + worker role)
- Supporting library project 1
- Supporting library project 2
- Web project
- Worker role project
Email Handler VS solution
- Cloud Service Project 2 (email handler)
- Supporting library project 1
- Supporting library project 2
- Email worker project
Additional Build Definition Configuration
The build definition themselves need to be tweaked due to the following reasons:
- We have multiple cloud service project configuration: development (local). staging, production, etc.
- We have multiple build configuration: debug, staging, production, etc. We use build configuration to include or exclude a certain code path using #if, #endif directive, etc., as well to do configuration transform on web.config or app.config (using SlowCheetah Visual Studio extension).
Therefore, we need to do extra build definition customization in the following sections:
- Process/Build/Projects: this need to point to the Visual Studio solution you wish to build (must only contain a single cloud service project).
- Process/Build/Configuration: this need to be configured to match the build configuration and platform that you are building for (i.e. Mixed Platform|Staging or Any CPU|Production).
- Process/Build/Advanced/MSBuild Arguments: you need to add /p:TargetProfile={your cloud project configuration setting target}, for example: /p:TargetProfile=Production if you are building for Production deployment where each configuration setting comes from the ServiceConfiguration.Production.cscfg file in the Cloud Service project.
- Process/Deployment/Deployment/Windows Azure Deployment Environment: you need to tweak this to suit your need. For example what Storage Account you wish the continuous deployment to use (It will upload the built package to the blob storage in the vsdeploy container), whether you wish it to go directly to Production slot or keep it in Staging slot for manual VIP swap, the Azure subscription, which cloud service to deploy to, etc.
I hope this post will help you if you ever found yourself in similar situation.
Further notes on Visual Studio solution splitting
The following has nothing to do with continuous deployment but we realized something else after having tons of issue with Azure .Net SDK upgrade and the way we split up our original VS solution (the one with multiple cloud service projects) into multiple VS solutions.
The problem originated with how we structure our solution, how the Azure .NET SDK upgrade tool and nuget works. We are using project dependencies and not binary dependencies for our own VS projects when establishing references between projects in the solution. We also have Azure DLLs (pulled via nuget package) referenced in multiple projects (not just the web project). And for some reasons, when we update a nuget package such as WindowsAzure.Storage in one of the refactored VS solutions, things will start breaking in the other refactored VS solution, vice versa (build failure, etc.). This has to do with how the reference dependencies is resolved by Visual Studio. When shared supporting project 1 is updated (via nuget) in VS solution 1, it will inject the path relative to that particular solution. When the same supporting project 1 is loaded in VS solution 2, it won’t be able to find the referred DLL in the specific package folder and it will fall back to an older Azure DLL in the C:\Program Files\Microsoft SDKs\Windows Azure\…\ref folder.
So, to solve this issue, we thing the following setup should work nicely.
Say you have 3 cloud services in your product. You would create the following VS solutions:
- A solution which sole purpose is for development only. This solution can have multiple cloud service projects inside of it (as per original). The purpose here is to minimize Azure DLLs and other nuget packages issues when upgrading Azure .Net SDK in the future. Any Azure .Net SDK and related nuget package upgrade should be done in this solution.
- Solution 1 that only contains cloud service project 1 and all other dependencies (i.e. cloud library, data access, etc.). This will be the designated build solution when deploying cloud service 1. You should not perform any nuget upgrade in this solution. As a matter of fact, you should not load this in Visual Studio to do any code alteration. This solution is purely for build and continuous deployment purposes.
- Solution 2 that only contains cloud service project 2 and all other dependencies (i.e. cloud library only). This will be the designated build solution when deploying cloud service 2. You should not perform any nuget upgrade in this solution. As a matter of fact, you should not load this in Visual Studio to do any code alteration. This solution is purely for build and continuous deployment purposes.
- Solution 3 for deploying cloud service 3… You should not perform any nuget upgrade in this solution. As a matter of fact, you should not load this in Visual Studio to do any code alteration. This solution is purely for build and continuous deployment purposes.
I think you get the idea.
We think having multiple solutions like so will simplify both Continuous Delivery and Azure SDK updates in the future.