I have tried every possible example I can come across yet have not been able to make a single one of these work. Has anyone managed to get a ServiceDefinition.csdef transform to actually work?
During each of the below attempts, I have used the ServiceDefinition.csdef in the Bin folder (after build) and then looked at the csdef in the package file. I was setting vmsize in the 'base' or original file to 'Other' (I know this is not a real size) and then uses a transform that should have changed it to 'Large' but the final file always showed 'Other'.
Fabriccontroller.net's Example
SkyLineTechnologies' Example
MSDN Blogger's Example
And about 3 or 4 others...
We build Umbraco based websites and host them on Azure. We setup 3 environments (QA, UAT, and LIVE) and on each environment we have 2 Web Roles (Front End and Back Office). The goal of transforming the ServiceDefinition.csdef is so that the following vmsizes are reached:
QA-FE: Small
QA-BO: Small
UAT-FE: Small
UAT-BO: Small
LIVE-FE: Large
LIVE-BO: Small
I also want to point out that I tried creating multiple Cloud Service Projects but as you can see by the requirements above, this makes it a bit 'odd'
Finally, the transform must be able to happen on our TFS Build Server (vNext).
I came up with my solution after reviewing a lot of different suggestions I found that parts of them worked but others did not. I ended up combining and simplifying what I found to work into this.
For this example, we have the following requirements:
Go to the Project Folder for the Azure Cloud Services Make a copy of the ServiceDefinition.csdef and name it ServiceDefinition.Base.csdef Add 3 files, ServiceDefinition.QA.csdef | ServiceDefinition.UAT.csdef | ServiceDefinition.LIVE.csdef Unload your Project in Visual Studio and edit the ccprog file Find the ItemGroup that contains the ServiceDefinition.csdef, which will look like this:
<ItemGroup>
<ServiceDefinition Include="ServiceDefinition.csdef" />
<ServiceConfiguration Include="ServiceConfiguration.QA.cscfg" />
<ServiceConfiguration Include="ServiceConfiguration.UAT.cscfg" />
<ServiceConfiguration Include="ServiceConfiguration.LIVE.cscfg" />
</ItemGroup>
Make it look like this:
<ItemGroup>
<ServiceDefinition Include="ServiceDefinition.csdef" />
<ServiceConfiguration Include="ServiceConfiguration.QA.cscfg" />
<ServiceConfiguration Include="ServiceConfiguration.UAT.cscfg" />
<ServiceConfiguration Include="ServiceConfiguration.LIVE.cscfg" />
<None Include="ServiceDefinition.Base.csdef" />
<None Include="ServiceDefinition.QA.csdef">
<DependentUpon>ServiceDefinition.csdef</DependentUpon>
</None>
<None Include="ServiceDefinition.UAT.csdef">
<DependentUpon>ServiceDefinition.csdef</DependentUpon>
</None>
<None Include="ServiceDefinition.LIVE.csdef">
<DependentUpon>ServiceDefinition.csdef</DependentUpon>
</None>
</ItemGroup>
Now go to the bottom of the ccprog file and between the Import
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v14.0\Web\Microsoft.Web.Publishing.targets" />
and the closing Project Tag
</Project>
Add the following:
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v14.0\Web\Microsoft.Web.Publishing.targets" />
<Target Name="BeforeBuild" Condition=" '$(Configuration)' != 'Debug' ">
<Message Text="Removing Read-Only Attribute from ServiceDefinition.csdef" />
<Exec Command="attrib -r $(ProjectDir)ServiceDefinition.csdef" />
<Message Text="Transforming ServiceDefinition.Base.csdef with ServiceDefinition.$(Configuration).csdef to create ServiceDefinition.csdef" />
<TransformXml Source="ServiceDefinition.Base.csdef" Transform="ServiceDefinition.$(Configuration).csdef" Destination="ServiceDefinition.csdef" />
</Target>
Save and Reload the project, if any error messages come up, correct the issue. Upon reload, your project file should look like this:
Open the ServiceDefinition.QA.csdef and add this:
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="AzureCloudTransform" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform" schemaVersion="2015-04.2.6">
<WebRole name="WebApplication" vmsize="Small" xdt:Transform="SetAttributes" xdt:Locator="Match(name)">
</WebRole>
</ServiceDefinition>
Save
Open the ServiceDefinition.UAT.csdef and add this:
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="AzureCloudTransform" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform" schemaVersion="2015-04.2.6">
<WebRole name="WebApplication" vmsize="Large" xdt:Transform="SetAttributes" xdt:Locator="Match(name)">
</WebRole>
</ServiceDefinition>
Save
Open the ServiceDefinition.LIVE.csdef and add this:
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="AzureCloudTransform" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform" schemaVersion="2015-04.2.6">
<WebRole name="WebApplication" vmsize="XLarge" xdt:Transform="SetAttributes" xdt:Locator="Match(name)">
</WebRole>
</ServiceDefinition>
Save
Done.
Now when you build in one of the Build Configurations, the transform will happen before the build which then allows VS to just run normally for the packaging of the files. The ServiceDefinition.csdef file will change prior to the build and be included in the package correct. The biggest reason I chose to do this transform this way is because it work on our Build Servers which are using vNext Build Definitions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With