Imagine that you were required to interface with an incompatible codebase. In .NET, we have the GAC (Global Assembly Cache) that helps us overcome situations known as DLL Hell… But times are changing and because we run software on virtual environments, we don’t have the luxury or interest of publishing our dependencies to the GAC.
I build cloud solutions for a living and sometimes, I’m faced with interesting challenges. In a recent project, I was asked to help my team design a public facing API that would interface with a backend. The team building the API solution agreed that it would be wise to keep our dependencies in check and run with the crowd. Remember, Windows Azure releases updates and features every 3 weeks!
Every week, someone from our team checked dependencies and tools for updates. Life was fantastic!
Then, it was time to integrate with, the other team’s code base, “the backend”. This is where things got interesting because our project was on the bleeding edge, but the backend wasn’t. Actually it was a couple versions behind on most of its dependencies. As you can imagine, this threw a wrench in our aspirations to keep up because we didn’t rely on the GAC to manage DLL versions.
Some of our common dependencies were backwards compatible, but others unleashed hidden dragons. Think about this for a second, how do you integrate multiple incompatible code bases to form an ecosystem?
You isolate them!
In order to execute both code bases independently, I decided to wrap the backend with a proxy that would execute in a separate AppDomain. The proxy was built as a console application and the WCF service is hosted in process. This simplified development and testing of the proxy.
Once we had our proxy, we needed to integrate and deploy to our Cloud Service Role instances. This is the step that proved to be a challenge. As it was impossible for us to drop the backend binaries into our API’s output directory, I decided to use post-build events to ZIP the Proxy’s output directory. The resulting archive was then included in the Cloud Service project and copied to its output directory. Then I configured a Startup Task that would UNZIP the proxy in folder located on the same level as bin and launched the Proxy as a background task.
But there was a catch, as some of you know, I’m not a big fan of command lines… So I pinged Mathieu Langis, who was kind enough to spend some time to help me finish setting up the Proxy startup task.
Creating an Archive on Build
The first thing I had to do, was to find a way to ZIP the output of each time I built my Proxy in order to place the archive in my Cloud Service.
Bing came up with a few good suggestions and finally decided to use 7zip from the command line.
To set a post-build event, go to the project’s properties and navigate to the Build Events tab. Then click on “Edit Post-Build…”
We used the following command to create the archive and to drop it into the Cloud Service.
$(ProjectDir)7za.exe a "$(SolutionDir)CloudService\Startup\$(ProjectName).zip" "$(TargetDir)*"
For this to work, you need to place a copy of 7za.exe at your project’s root.
Once the command completes, you will find your archive located in the solution folder “CloudService\Startup\”.
Deploying the Proxy Archive with the Cloud Service
Once the archive is placed in the “CloudService\Startup\” folder, it’s not time to make sure it gets deployed with the Cloud Service.
Be sure to include a copy of “7za.exe” and a copy of “Proxy.zip” in the Cloud Service Project. Then right click both of them and set the File Properties so that they are set to “Copy Always”.
Configuring the Startup Task
Once all the pieces are in place, it’s time to create and configure our Startup Task.
Add a new cmd file to the Cloud Service under the Startup folder. This location is not important, in our case it’s a matter of convenience.
Be sure to save the cmd file by setting the encoding to ANSI
We used to following script to extract the Proxy from the archive to a folder located outside the %ROLEROOT%\approot\bin folder.
cd %ROLEROOT%\approot\bin\Startup\
7za.exe e Proxy.zip -o..\..\Startup\Proxy –y
Then we use the following script to start the Proxy.
cd %ROLEROOT%\approot\Startup\Proxy
start Proxy.exe
Configuring the startup task consists of editing the ServiceDefinition.csdef located in the Cloud Project. Adding the task to the Startup tag found under both the WorkerRole and the WebRole tags.
<Task commandLine="Startup/StartupTask.cmd" executionContext="elevated" taskType="background">
</Task>
</Startup>
The task is configured to execute with elevated rights and as a background task. This will allow the Role to continue it’s startup process without blocking and waiting for the startup task to complete.
Find out More
- Configuring external startup tasks on an Azure cloud service
- Run Startup Tasks in Windows Azure
- Strategies for Writing Startup Tasks that can run Multiple Times
- Best Practices for Startup Tasks
- Define Startup Tasks for a Role
- WorkerRole Schema
- WebRole Schema
- Define Environment Variables Before a Role Starts
- Use Local Storage to Store Files During Startup
- Make a Startup Task Perform Different Actions on the Compute Emulator and the Cloud
- Use AppCmd.exe to Configure IIS at Startup
- Add Firewall Rules By Using a Startup Task
- How to: Host a WCF Service in a Managed Application
- WCF Tutorial – Basic Interprocess Communication
- WCF by example on netNamedPipeBinding
Please note that ‘7za.exe a’ adds files to an archive, it doesn’t overwrite the archive. So if you make changes to your project that’s being packed and some files are removed from the output they will still remain in the archive. This may or may not cause problems so you are better off deleting the archive prior to updating it.
LikeLike
that’s an excellent point, thanks Andrei
LikeLike