Add a web.config transform and a publish profile in Visual Studio 2013

If you need to deploy your app to multiple environments, like in most corporate IT shops (dev, QA, Staging, Training, Production, etc…), then you’ll need to have multiple versions of your config files, or better yet, one config file and “transform” files (one for each deployment environment) that describe ONLY the differences between the main config file and that particular environment.

For example, the connection string in the QA environment is likely different than the connection string in your Dev environment, which is different than your QA environment and again different in your live Production environment.

[GARD]

I’m not going to explain how to WRITE a config transform (how to tell it what needs to change).  At least, not in THIS article.  But I will tell you how to tell Visual Studio that you have multiple environments and how to make Visual Studio create the basic config transforms for you.

In this example, I’m creating a WCF Service application (works the same with pretty much any web type of application).

  1. Are you deploying a NON Asp.Net app (like a click-once app or a WinForms or WPF app)?  If so, install the Nuget package “Slow Cheetah”.  Why?  Because Visual Studio has built in support for all this for web.config files, but NOT for app.config files.  Slow Cheetah lets you make transforms for ANY file in your project.
  2. Right-Click your project and choose “Publish…”transform_01
  3. In the “Publish Web” dialog, choose “Custom”transform_02
  4. Give it a name.  NOTE!  If you have a different admin managing your deployment and/or build servers, you may want to check with them on what name to use, because it will make a difference between whether your stuff works or doesn’t!  For this example, I’ll call the transform “QA”transform_03
  5. Choose your deployment method (web publish, file copy, etc…).  For this example, I’m choosing “File System” since it requires fewer settings to fill out and I’m going to leave “Target location:” blank.  My deployment admin will fill that in later, so I don’t even need to know this.  Click “Next”.
  6. Choose whether this deployment should be a “Release” or a “Debug” deployment.  This will cause it to build it as debug or release. (You will also have a debug and a release transform of your web.config file and this new QA transform will inherit from either of those).transform_04
    1. Expand “File Publish Options” and check the items you need, then click “Next”
  7. Final screen in the wizard.  Click “Close”.  You can’t click “Publish” if you left the target path blank above.

[GARD]

You’ve now successfully created a publish profile.

transform_05 QA done

Now you’ll need to create a Web.config transform for this profile.

  1. Rich-Click your QA.pubxml file and choose “Add Config Transform”.  Do NOT choose “Add Transform” if you have Slow Cheetah installed.transform_06 QA Add Transform

You now have a new Web.QA.config file.

transform_07 Complete

You can now code your base Web.config file the way you need it to run locally during development.  In your Web.QA.config file, you can add transforms to modify settings in your web.config file so that when you build for that environment, Visual Studio will produce a web.config file that’s right for that environment.

You can repeat these steps to add as many publish profiles as you need.

See these images?

image

You’ll find actual working versions of them at the top and bottom of this article. Please click the appropriate buttons in it to let your friends know about this article.

Check back later for updates too!

 

 

 

Web.config and App.config variables can be fully type safe

I’m going to introduce a MUCH better way of accessing your variables that you have created in your web.config or app.config file.  Most likely, you’re probably storing your variables in your .config file like this:

Click here to follow me on Google+.

 <appSettings> <add key="EMailAddress" value="me@something.com"/> <add key="IsProduction" value="true"/> <add key="MaxWait" value="15"/> appSettings>

And your code to access them probably looks like this:

this.EMailAddressLabel.Text = ConfigurationManager.AppSettings["EMailAddress"];if (ConfigurationManager.AppSettings["IsProduction"] == "true") this.NotProdNotifyLabel.visible = false;else this.NotProdNotifyLabel.visible = true;this.MaxWaitLabel.Text = "Maximum wait time is " + ConfigurationManager.AppSettings["MaxWait"] + " seconds";

That’s an awful lot of typing, has the potential for typos that aren’t caught by the editor or the compiler, doesn’t have intellisense, and is not type safe.

Solution!

Visual Studio has a very easy to use and very powerful feature for creating and accessing config variables.

Now, depending on what version of Visual Studio you’re using, things could be different.  As of this writing, the latest version is Visual Studio 2010.  But, this feature is available going all the way back to the original version of Visual Studio .Net back in February 2003.  So, it’s supported in all versions, but there are differences, not in how you do it, but in what choices you’ve already made for existing apps.  First, I’ll discuss doing this the right way when creating a new app:

BTW, this works for ALL .Net apps, not just ASP.Net web apps.  It works for WinForms, ASP.Net MVC, ASP.Net, Console apps, Windows Service Apps…

I’ll be using an ASP.Net WebForms app as an example, because that’s where the differences lie between the different version of Visual Studio.Net.

First, we’ll work with making a New app.

    1. Create a web app app.  Depending on your version of Visual Studio, you might have an option for “Web Site”.  DON’T CHOOSE THAT!  This whole solution is unavailable for web sites.  It MUST be a web app!

 

  • Right-click your project and choose “Properties:

 

  1. image

 

  • Click on the “Settings” tab.

 

  1. image

 

  • Click on the link, “This project does not contain a default settings file.  Click here to create one.”

 

  1. image

Now, your app contains what’s needed to support your simple typed config variables.  Notice the new stuff added to your project?

image

Now, never look at it again.  I just wanted you to see that it’s there.  This adds no complication to your life because you’ll never use it directly.  It’s just generated code.  Put it out of your mind and never think of it again.

Notice the grid that showed up on the screen?

image

This is where you’ll create your config variables… not in the config file itself.  This simple tool will automatically add them to the config file for you.  You don’t have to putz around with the messy config file anymore for your config variables.  Now, let’s add the 3 config variables we used the old way from the top of this article:

For each variable we create, we can choose the type of that variable!  Check out what happens when I create the IsProduction variable:

image

I picked “bool” from the “Type” drop down list.  Look at the “Value” column.  Notice that it knows what is valid for a boolean?  I’ll pick “True”.

Now, when I add MaxWait, I’ve got some options.  I can make it an int to represent number of seconds, but in reality, it’s representing a time span.  Guess what?  .Net has a TimeSpan type!

image

image

It inserts a value for me, showing me the format I need.  That’s HH:MM:SS, BTW.  I can add a decimal after the seconds to get milliseconds, if I want.  There’s a way to do days too, but I’ll let you figure that out.

I’m going to enter 15 seconds:

image

Now, this is important (but simple).  I need to hit “save”.

image

Now, look at what it did to the config file:

image

image

Now, there’s one more thing I want to draw your attention to… and it’s not important that you know this because you’ll never need to mess with this, but I want to give you a glimpse under the hood of what else has happened:

image

Pop open the Settings.settings branch and open the Settings.Designer.cs file:

 

 1: //------------------------------------------------------------------------------
 2: // 
 3: // This code was generated by a tool.
 4: // Runtime Version:4.0.30319.237
 5: //
 6: // Changes to this file may cause incorrect behavior and will be lost if
 7: // the code is regenerated.
 8: // 
 9: //------------------------------------------------------------------------------
 10: 
 11: namespace ConfigVarsSample.Properties {
 12: 
 13: 
 14:     [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
 15:     [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")]
 16:  internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
 17: 
 18:  private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
 19: 
 20:  public static Settings Default {
 21:             get {
 22:  return defaultInstance;
 23:             }
 24:         }
 25: 
 26:         [global::System.Configuration.ApplicationScopedSettingAttribute()]
 27:         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
 28:         [global::System.Configuration.DefaultSettingValueAttribute("me@something.com")]
 29:  public string EMailAddress {
 30:             get {
 31:  return ((string)(this["EMailAddress"]));
 32:             }
 33:         }
 34: 
 35:         [global::System.Configuration.ApplicationScopedSettingAttribute()]
 36:         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
 37:         [global::System.Configuration.DefaultSettingValueAttribute("True")]
 38:  public bool IsProduction {
 39:             get {
 40:  return ((bool)(this["IsProduction"]));
 41:             }
 42:         }
 43: 
 44:         [global::System.Configuration.ApplicationScopedSettingAttribute()]
 45:         [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
 46:         [global::System.Configuration.DefaultSettingValueAttribute("00:00:15")]
 47:  public global::System.TimeSpan MaxWait {
 48:             get {
 49:  return ((global::System.TimeSpan)(this["MaxWait"]));
 50:             }
 51:         }
 52:     }
 53: }

This is the code that got generated for you.  Now, put it out of your mind (again), because you’ll never actually edit this file.

Now, remember the old way of accessing the config variables?

this.EMailAddressLabel.Text = ConfigurationManager.AppSettings["EMailAddress"];if (ConfigurationManager.AppSettings["IsProduction"] == "true") this.NotProdNotifyLabel.visible = false;else this.NotProdNotifyLabel.visible = true;this.MaxWaitLabel.Text = "Maximum wait time is " + ConfigurationManager.AppSettings["MaxWait"] + " seconds";

Here’s the new way:

Add this to your using section:

using

 

ConfigVarsSample.Properties;

And in your code, you do this:

image

Notice how you get intellisense?!?!?  Let’s continue:

var settings = new Settings();this.EMailAddressLabel.Text = settings.EMailAddress;this.NotProdNotifyLabel.visible = !settings.IsProduction;this.MaxWaitLabel.Text = "Maximum wait time is " + settings.MaxWait.ToString();

See how much cleaner this code is?  And, since it’s typed, you can use the IsProduction variable as a boolean rather than examining the text value of it.  The MaxWait variable can actually be used in time and date functions and directly in calculations!

What have you gained?

    1. Intellisense.

 

  • Edit time typo checking.

 

 

  • Compile time error checking.

 

 

  • Strongly typed variables.

 

 

  • Code that won’t fail at run time.

 

 

  • .config files that you don’t have to edit directly as often.

 

 

  • Increased productivity.

 

See this image?

image_thumb26

You’ll find an actual working version of it at the bottom of this article. Please click the appropriate buttons in it to let your friends know about this article.

Check back later for updates too!

Click here to follow me on Google+.