20

I have a Windows Azure site which is deployed to two separate hosted services. One for test, one for production. When we're ready to push to production, we spin up a staging deployment in the production service, push there, then do a VIP swap. All good.

The question is, now we want to move up from XS web instances, but it doesn't really make sense to spend the extra money on the test deployment. Is there any way to use an XS instance for test, and then say medium instances for production? I know I can change the number of instances for each service config, but I can only change the instance size for all configs.

I'm thinking of just leaving it XS in the config, and then remembering to switch it to Medium before I deploy to production. Is there any reason why I shouldn't do this? Is there a better way?

Cheers!

ManicBlowfish
  • 2,149
  • 2
  • 19
  • 29
  • 1
    May also want to check out built-in support for multiple cloud profiles: http://www.nickharris.net/2011/08/using-the-new-windows-azure-tools-v1-4-for-vs2010/ or even more super-dynamic: http://blogs.msdn.com/b/philliphoff/archive/2012/07/02/transform-windows-azure-service-model-files-during-packaging.aspx – codingoutloud Feb 01 '13 at 18:42
  • 1
    another handy article here http://blogs.msdn.com/b/microsoft_press/archive/2015/03/12/guest-article-microsoft-azure-dev-test-scenario-considerations.aspx – Rory Feb 03 '16 at 14:21

5 Answers5

23

There are a few ways to do this... Simpler way is to do a little "hacking" of the CCPROJ file:

1) create a clone of the CSDEF file for every environment that matches the Configuration Name (Release/Debug/QA/UAT/etc): ServiceDefinition.Release.csdef, ServiceDefinition.Debug.csdef, etc.

2) Add those files manually to the CCPROJ file by using a notepad editor

3) Define a Pre-Build Event command that copies the ServiceDefinition.$(ConfigurationName).csdef into ServiceDefintion.csdef

voila, now your ServiceDefintion will adapt to whatever configuration you're using.

If you want to get fancier or see more details, check out this blog entry that can help you switch all sorts of settings in unison

http://www.paraleap.com/blog/post/Managing-environments-in-a-distributed-Azure-or-other-cloud-based-NET-solution.aspx

Edit: Here is a config that works. Notice that other files are included as type "None" instead of ServiceDefinition to avoid the multiple definitions error.

  <ItemGroup>
    <ServiceConfiguration Include="ServiceConfiguration.Local.cscfg" />
    <ServiceConfiguration Include="ServiceConfiguration.Development 1.cscfg" />
    <ServiceConfiguration Include="ServiceConfiguration.Development 2.cscfg" />
    <ServiceConfiguration Include="ServiceConfiguration.Local Dev 1.cscfg" />
    <ServiceConfiguration Include="ServiceConfiguration.Local Dev 2.cscfg" />
    <ServiceConfiguration Include="ServiceConfiguration.QA 1.cscfg" />
    <ServiceConfiguration Include="ServiceConfiguration.QA 2.cscfg" />
    <ServiceConfiguration Include="ServiceConfiguration.Pre-Production 1.cscfg" />
    <ServiceConfiguration Include="ServiceConfiguration.Production.cscfg" />
    <ServiceDefinition Include="ServiceDefinition.csdef" />
    <None Include="ServiceDefinition.Local.csdef" />
    <None Include="ServiceDefinition.Development 1.csdef" />
    <None Include="ServiceDefinition.Development 2.csdef" />
    <None Include="ServiceDefinition.Local Dev 1.csdef" />
    <None Include="ServiceDefinition.Local Dev 2.csdef" />
    <None Include="ServiceDefinition.QA 1.csdef" />
    <None Include="ServiceDefinition.QA 2.csdef" />
    <None Include="ServiceDefinition.Pre-Production 1.csdef" />
    <None Include="ServiceDefinition.Production.csdef" />
  </ItemGroup>
jimhark
  • 4,613
  • 1
  • 23
  • 26
Igorek
  • 15,306
  • 2
  • 44
  • 88
  • Thanks much. Only issue I had was the Azure project would not build with multiple .csdef files in it. Just omit step #2 in your solution, though, and all seems to work. Error was "Microsoft.WindowsAzure.targets(845,5): error : WAT020 : Only one service definition can be active." – ManicBlowfish Jun 25 '12 at 16:42
  • @Igorek: Your blog post is missing the images. Can that be fixed? I was also interested in the solution. – DeepSpace101 Jan 18 '13 at 05:53
  • @Sid: images have been restored. Thanks for patience – Igorek Feb 05 '13 at 02:08
14

You can use the Web Publishing TransformXml MSBuild task to transform only the parts of the ServiceDefinition you want (like you can do now with Web.Config).

  • Create a ServiceDefinition.[BuildConfigName].csdef file next to the ServiceDefinition.csdef file (you'll probably need to do this in File Explorer)
  • Create the transform file like you'd created a Web.config transform. I explicitly set the root namespace, just in case, so my root element is:
  <ServiceDefinition name="Cloud.JobsWorker" 
          xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" 
          xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"
          schemaVersion="2013-10.2.2">
  • Manually add it to your ccproj using:
  <ServiceDefinition Include="ServiceDefinition.csdef" />
  <None Include="ServiceDefinition.Release.csdef" />
  • At the bottom of your project include:
  <UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Web\Microsoft.Web.Publishing.Tasks.dll" />
  <PropertyGroup>
    <ServiceDefinitionTransform>ServiceDefinition.$(Configuration).csdef</ServiceDefinitionTransform>
  </PropertyGroup>
  <Target Name="TransformServiceDefinition" BeforeTargets="ResolveServiceDefinition" Condition="exists('$(ServiceDefinitionTransform)')">
    <!-- Generate transformed service config in the intermediate directory -->
    <TransformXml Source="@(ServiceDefinition)" Destination="$(IntermediateOutputPath)%(Filename)%(Extension)" Transform="$(ServiceDefinitionTransform)" />
    <!--Force build process to use the transformed configuration file from now on.-->
    <ItemGroup>
      <ServiceDefinition Remove="ServiceDefinition.csdef" />
      <ServiceDefinition Include="$(IntermediateOutputPath)ServiceDefinition.csdef" />
    </ItemGroup>
  </Target>

When you package or publish your cloud app, your csdef should be transformed depending on the build config you're using.

This is adapted from here: http://blogs.staykov.net/2011/06/windows-azure-configuration-settings.html

David Faivre
  • 2,152
  • 3
  • 22
  • 25
  • 1
    Slightly more work to set up than the accepted answer, but I prefer this one for a few reasons: it's an opt-in solution, it minimizes duplication and maintenance effort (you don't end up having tons of csdef files to change when adding or removing a Setting, for instance), and it doesn't play around too much with files as copying using Pre-Build steps would. Still, both answers are great! – mbargiel Jun 09 '15 at 20:28
  • This works fine for ServiceDefinition but ServiceConfiguration is not working as it still using the default one – user1754675 Jun 03 '16 at 15:01
  • When you say "At the bottom of your project include" is this in the ServiceDefinition file or a separate file? – Stephen Oct 04 '16 at 10:07
  • The bottom of your project file that the ServiceDefinition file is in. – David Faivre Oct 04 '16 at 21:46
  • Good solution. See [my answer](http://stackoverflow.com/a/43653168/1756017) for few comments. – Oleksii Iaroshchuk Apr 27 '17 at 08:59
2

Using transformation as David Faivre suggested is much cleaner and without the overhead to update all files after adding single property.

This is the transformation xml for changing vm size:

<?xml version="1.0"?>
<ServiceDefinition name="CloudServiceName" 
                   xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition" schemaVersion="2015-04.2.6" 
                   xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <WorkerRole name="WorkerRoleName.Role" vmsize="Medium" xdt:Transform="SetAttributes" xdt:Locator="Match(name)" />
</ServiceDefinition>
Community
  • 1
  • 1
Kobynet
  • 912
  • 11
  • 23
1

VM size is handled in the ServiceDefinition.csdef file, which is something you can't edit at run or deploy time. You would need to change the setting in the .csdef, repackage your solution, and then redeploy.

One solution may be to have multiple Windows Azure deployment projects set up. One project would be your "test" project that has the .csdef configured to use a XS. Another project would be the "production" project that uses a larger instance. This would allow you to use the standard Windows Azure / Visual Studio tools to manage the project - which may be nice depending on your process.

mcollier
  • 3,703
  • 13
  • 12
0

David Faivre proposed a good solution. Few comments from me:

  1. If your ServiceDefinition file contains links to some directories (e.g. section), than there will be an error caused by the fact that transformed file is in intermediate directory. For my use I solved this problem by placing transformed file alongside original ServiceDefinition.csdef (don't forget to add *.transformed into .gitignore):

<TransformXml Source="@(ServiceDefinition)" Destination="ServiceDefinition.csdef.transformed" Transform="$(ServiceDefinitionTransform)" />

  1. $(Configuration) variable corresponds to Build configuration (Debug, Release etc.). If you want to have profile specific transformation (corresponding to ServiceConfiguration..cscfg), you need to use $(TargetProfile) variable:

<ServiceDefinitionTransform>ServiceDefinition.$(TargetProfile).csdef</ServiceDefinitionTransform>

Community
  • 1
  • 1