In a previous post I introduced the concept of Role Content Folders and how they can be used to deploy additional content (e.g. configuration files, runtime components, etc.) to the virtual machine for a Windows Azure application role. That post was written from the perspective of a developer working within Visual Studio and works great when the content is relatively static and specific to a single project. However, this feature works less well in cases where the content is more dynamic (i.e. where the additional content is not known until package-time) or when the content is used across several roles or applications. Fortunately, the packaging of Role Content Folders within Visual Studio is built upon more general MSBuild infrastructure which we can extend to package additional, arbitrary content.
In v1.7, the targets file for Windows Azure projects contains a new packaging phase (i.e. high-level target) called AddRoleContent. In this phase, various sub-targets identify the Role Content Folders defined by the project file, prepare the files within those folders for packaging, and then inject appropriate elements into the Service Definition (.csdef) file such that those files will be packaged when the process invokes CSPack. The AzureRoleContent MSBuild item group ultimately determines what folders will be packaged and for which roles. An AzureRoleContent item contains the following metadata:
To inject additional content into the package, one must add new AzureRoleContent items prior to the last step of this packaging phase. A convenient place to do this is within an override of the BeforeAddRoleContent target. An alternative is to add a custom target to the beginning of the target list CoreAddRoleContentDependsOn MSBuild property. This latter approach can be useful for cases where you customize many Windows Azure projects in the same way, as it ensures that individual Azure projects do not interfere with the customization if a project were to independently override the BeforeAddRoleContent target.
Let’s suppose we have the following:
The first step is to edit the Windows Azure project file and override the BeforeAddRoleContent target. Next, the target will create a new item group, AzureRoleContent, that includes the AdditionalContent folder. We’ll then add metadata to the item group to specify that it be deployed with the web role, MyWebRole, as well as deployed to the APPROOT\AdditionalContent folder. In the end, we will have a project file that looks something like:
. . . <Import Project="$(CloudExtensionsDir)Microsoft.WindowsAzure.targets" /> <Target Name="BeforeAddRoleContent"> <ItemGroup> <AzureRoleContent Include="AdditionalContent"> <RoleName>MyWebRole</RoleName> <Destination>AdditionalContent</Destination> </AzureRoleContent> </ItemGroup> </Target> . . .
When a package is built and/or deployed you will then see the AdditionalContent folder, with its AdditionalContent.xml file, in the package layout and/or on the virtual machine.
Now what would happen if we omitted the Destination metadata from the item group, as in the following example?
. . . <AzureRoleContent Include="AdditionalContent"> <RoleName>MyWebRole</RoleName> <!--<Destination>AdditionalContent</Destination>--> </AzureRoleContent> . . .
In this example, the content in the AdditionalContent folder will deployed directly to APPROOT, with no corresponding subfolder. This can be very useful when you need to deploy a configuration file to APPROOT. However, note that this can result in name collisions between files deployed by the role project and files deployed through this Role Content Folder mechanism. You will not get any warnings or errors from CSPack (or the Tools) when this happens, so beware!
Role Content Folders can be a great option when you have additional content to deploy to a role of a Windows Azure application, whether used to deploy static content within Visual Studio or used in conjunction with the underlying infrastructure to deploy more dynamic content.