Our team recently ran into a strange issue. Our Windows Phone application targets Silverlight 8.1 but we have several WinRT 8.1 based background tasks. Recen...
Transform Windows Azure Service Model Files During Packaging
The latest versions of the Windows Azure Tools for Visual Studio have the ability to maintain multiple versions of the Service Configuration (.cscfg) file. The developer is then prompted to select the version to accompany a deployment, whether it’s going to Windows Azure or the development fabric (i.e. the emulator). However, sometimes a developer needs to do something a little more dynamic, where elements of the Service Configuration file must be generated on-the-fly before deployment.
The Tools generate a Windows Azure package via a process driven by MSBuild. The process already performs certain transformations of the Service Configuration file from the original hosted by the project. These transformations include:
- Adding configuration setting values when IntelliTrace or Profiling are enabled during publishing
- Adding configuration setting values when Remote Desktop is enabled during publishing
- Adding endpoints when WebDeploy is enabled
This transformation process is easily extensible (for certain definitions of “easy”). To do this, some of the MSBuild concepts you will need are:
- TargetProfile: This MSBuild property corresponds to the configuration selected for packaging or deployment, e.g. “Local” or “Cloud”.
- SourceServiceConfiguration: This MSBuild item group* corresponds to the Service Configuration file hosted by the project that was selected for deployment (based on the value of the TargetProfile property), e.g. ServiceConfiguration.Cloud.cscfg.
- TargetServiceConfiguration: This MSBuild item group* corresponds to the actual Service Configuration file that will be deployed. This file begins as a copy of SourceServiceConfiguration but may then be transformed based on the selected publish settings.
TransformServiceModel: This target represents the part of the build and package process that controls transformation of the Service Configuration file. It can be extended by overriding the BeforeTransformServiceModel or AfterTransformServiceModel targets, or by adding new targets to the CoreTransformServiceModelDependsOn MSBuild property.
*Despite being an item group, it only ever contains a single file.
To add a new transformation step, start by updating the project file (.ccproj). Add a new property group that redefines CoreTransformServiceModelDependsOn, adding a new target to the end of the original value. Next, define the new target; it will now get called during the transformation phase of the package process. In the target, open the file represented by the @(TargetServiceConfiguration)item group, modify it as desired, and then save it.
<Import Project="$(CloudExtensionsDir)Microsoft.WindowsAzure.targets" />
<!-- Perform transformation of @(TargetServiceConfiguration) here. –>
To see a practical example of this technique used to workaround an issue encountered by some customers in the v1.7 Tools, read this MSDN forum post.
Don’t Forget the Service Definition File!
The Service Definition (.csdef) file is intended to be the same across all deployments of a Windows Azure application. This is why it’s located in the package rather than alongside the package like the Service Configuration file. However, there are still scenarios where a developer may wish to change the Service Definition dynamically, based on the environment for which the application is packaged. Even though the Tools do not support multiple Service Definition files hosted by a project, they undergo a very similar transformation process that can be extended in the same way, using similar MSBuild concepts:
- SourceServiceDefinition: This MSBuild item group* corresponds to the Service Definition file hosted by the project, e.g. ServiceDefinition.csdef.
- TargetServiceDefinition: This MSBuild item group* corresponds to the actual Service Definition file that will be packaged. This file begins as a copy of SourceServiceDefinition but may then be transformed based on the selected publish settings.
*Despite being an item group, it only ever contains a single file.
You can apply transformations to the Service Definition file using the @(TargetServiceDefinition)item group in the same target as you do the Service Configuration file.
Project File Customization or Common Target?
If the transformation scenario is specific to a single Windows Azure project, then it makes sense to alter the build and package process via that project file directly. However, if the scenario is common it may make sense to split out the customization into a separate targets file. This target file can then be imported in various ways depending on how commonly it’s needed:
- (Option #1) Import the targets directly from the project: In this option, the targets file is stored in a well-known location (preferably in a path that can be specified relative to any project which has occasion to use it). The project file is then modified by hand to import the targets file after the import of the Windows Azure targets file. This option is suitable when a limited, related set of Windows Azure projects (e.g. within the same solution) need the same customization.
- (Option #2) Globally import the targets: In this option, the targets file is placed in a well known location on the machine which will cause it to be automatically imported by every Windows Azure application on that machine. This option is suitable when any Windows Azure project might need the same customization. To have a target file imported automatically by all Windows Azure projects, add the file to this location:
<Program Files (x86)>\MSBuild\Microsoft\VisualStudio\<VS Version>\Windows Azure Tools\<Tools Version>\ImportAfter\
For example, on a machine with Visual Studio 2012 installed and version 1.7 of the tools the location would be:
C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v11.0\Windows Azure Tools\1.7\ImportAfter\
Note that, since this target is imported by all Windows Azure projects on the machine, it should be robust enough to handle cases where the customization is not necessary.
But I Want Web.config-style Transforms!
A common question is “why don’t the Tools support multiple Service Configuration files using web.config-style transforms?” (This transformation mechanism is being more commonly referred to as SlowCheeta.) Well, the short answer is: because the Tools has a designer over the Service Model files and web.config does not. Using multiple, complete, configuration files to represent different configuration environments is far less complex to automate via a design surface like the Role Editor (a.k.a. Service Model UI). In addition, it’s easier for the beginning Windows Azure developer to understand complete files and not be forced to learn the complex XML matching and transformation syntax.
For those that still want web.config-style transformations, you can use the same techniques described above to get close to the familiar web application project experience. Start by updating the project file (.ccproj). Add a new property group that redefines CoreTransformServiceModelDependsOn, adding a new target to the end of the original value. Next, add a UsingTask element that refers to the TransformXml task in the web application publishing tasks assembly. Define the new target; it will now get called during the transformation phase of the package process. In the target, call the TransformXml task using the @(TargetServiceConfiguration) item group as both the source and destination, and specify an arbitrary transform file. In the example below, I’m choosing a transform file based on the current TargetProfile. For example, if the TargetProfile is “Cloud” meaning the ServiceConfiguration.Cloud.cscfg file will be deployed, the task will transform the source file using the file ServiceConfiguration.Cloud.Transform.cscfg, if it exists. (If it does not exist, no transform is performed.)
< Import Project="$(CloudExtensionsDir)Microsoft.WindowsAzure.targets" />
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v11.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
<Target Name="PerformXmlTransform" Condition=" Exists('ServiceConfiguration.$(TargetProfile).Transform.cscfg') ">
<Message importance="high" Text="Transformed @(TargetServiceConfiguration) using ServiceConfiguration.$(TargetProfile).Transform.cscfg." />
To sum up, if you are willing to spend some time to learn a few basic MSBuild concepts, the Windows Azure Tools for Visual Studio offers a lot of packaging flexibility. If you have custom packaging scenarios that the Tools do not support directly, consider using the Tools extensibility to add your own!
This post was migrated from my MSDN blog, Visual Studio Tools and Anything Else I Can Think Of, and written as a Microsoft employee.
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 ...
The latest versions of the Windows Azure Tools for Visual Studio have the ability to maintain multiple versions of the Service Configuration (.cscfg) file.&n...
When a package fails to deploy to Windows Azure (or deploys but its roles fail to start properly) it can be difficult to determine what went wrong. In many c...
Windows Azure applications often need to package and deploy additional content. This could be advanced configuration files such as the diagnostics.wadcfg for...
The LINQ-to-DASL provider of the Office Interop API Extensions provides a very limited set of mappings between its query types and their associated DASL prop...
When your LINQ-to-DASL queries do not return the results you expect, how do you determine where the problem is? The issue could be that the query simpl...
I received an email over the weekend asking why the following LINQ to DASL query threw an exception: Outlook.Folder folder = (Outlook.Folder)Application.Se...
Now that the Office Interop API Extensions have been released, I thought I would post a complete walkthrough of a simple LINQ to DASL application. Let's star...
One of the disadvantages of C# compared with VB is its lack of support for parameterized properties. Instead, parameterized properties in C# are exposed as ...
As announced in Andrew Whitechapel’s post, version 1.0 of the VSTO Power Tools have been released! One of those tools is the Office Interop API Extensions, a...
In an earlier post I discussed LINQ to DASL, part of the Office Interop API Extensions, which is one of the forthcoming VSTO Power Tools. LINQ to DASL ...
In my last post I talked about LINQ to DASL, a LINQ provider that converts query expressions into their DASL equivalent in order to efficiently filter item c...
Quick, tell me what the following code does:
I like VSTO. I like C#. What I don’t like is having to write VSTO code in C# like:
Yesterday I gave a presentation on VSTO at the third annual Portland Code Camp. I demonstrated an Outlook 2007 add-in that used Outlook Form Regions, WCF, an...