Deploy ASP.NET Web Applications with Web Deployment Projects

Posted by Ben Griswold on Johnny Coder See other posts from Johnny Coder or by Ben Griswold
Published on Thu, 07 Jan 2010 23:35:26 +0000 Indexed on 2010/03/18 22:11 UTC
Read the original article Hit count: 1057

One may quickly build and deploy an ASP.NET web application via the Publish option in Visual Studio.  This option works great for most simple deployment scenarios but it won’t always cut it.  Let’s say you need to automate your deployments. Or you have environment-specific configuration settings. Or you need to execute pre/post build operations when you do your builds.  If so, you should consider using Web Deployment Projects.

image

The Web Deployment Project type doesn’t come out-of-the-box with Visual Studio 2008.  You’ll need to Download Visual Studio® 2008 Web Deployment Projects – RTW and install if you want to follow along with this tutorial.

I’ve created a shiny new ASP.NET MVC project.  Web Deployment Projects work with websites, web applications and MVC projects so feel free to go with any web project type you’d like. 

image

Once your web application is in place, it’s time to add the Web Deployment project.  You can hunt and peck around the File > New > New Project… dialogue as long as you’d like, but you aren’t going to find what you need.  Instead, select the web project and then choose the “Add Web Deployment Project…” hiding behind the Build menu option.

image

I prefer to name my projects based on the environment in which I plan to deploy.  In this case, I’ll be rolling to the QA machine.

image

Don’t expect too much to happen at this point.  A seemingly empty project with a funny icon will be added to your solution.  That’s it.

image

I want to take a minute and talk about configuration settings before we continue.  Some of the common settings which might change from environment to environment are appSettings, connectionStrings and mailSettings.  Here’s a look at my updated web.config:

  1. <appSettings>
  2.   <add key="MvcApplication293.Url" value="http://localhost:50596/" />    
  3. </appSettings>
  4. <connectionStrings>
  5.   <add name="ApplicationServices"
  6.        connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true"
  7.        providerName="System.Data.SqlClient"/>
  8. </connectionStrings>
  9.  
  10. <system.net>
  11.   <mailSettings>
  12.     <smtp from="[email protected]">
  13.         <network host="server.com" userName="username" password="password" port="587" defaultCredentials="false"/>
  14.     </smtp>
  15.   </mailSettings>
  16. </system.net>

I want to update these values prior to deploying to the QA environment.  There are variations to this approach, but I like to maintain environment-specific settings for each of the web.config sections in the Config/[Environment] project folders.  I’ve provided a screenshot of the QA environment settings below.

image

It may be obvious what one should include in each of the three files.  Basically, it is a copy of the associated web.config section with updated setting values.  For example, the AppSettings.config file may include a reference to the QA web url, the DB.config would include the QA database server and login information and the StmpSettings.config would include a QA Stmp server and user information.

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <appSettings>
  3.   <add key="MvcApplication293.Url" value="http://qa.MvcApplicatinon293.com/" />
  4. </appSettings>

AppSettings.config 

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <connectionStrings>
  3.   <add name="ApplicationServices"
  4.        connectionString="server=QAServer;integrated security=SSPI;database=MvcApplication293"
  5.        providerName="System.Data.SqlClient"/>  
  6. </connectionStrings>

Db.config 

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <smtp from="[email protected]">
  3.     <network host="qaserver.com" userName="qausername" password="qapassword" port="587" defaultCredentials="false"/>
  4. </smtp>

SmtpSettings.config 

I think our web project is ready to deploy.  Now, it’s time to concentrate on the Web Deployment Project itself.  Right-click on the project file and open the Property Pages.

image

The first thing to call out is the Configuration dropdown.  I only deploy a project which is built in Release Mode so I only setup the Web Deployment Project for this mode.  (This is when you change the Configuration selection to “Release.”)  I typically keep the Output Folder default value – .\Release\.  When the application is built, all artifacts will be dropped in the .\Release\ folder relative to the Web Deployment Project root.  The final option may be up for some debate.  I like to roll out updatable websites so I select the “Allow this precompiled site to be updatable” option.  I really do like to follow standard SDLC processes when I release my software but there are those times when you just have to make a hotfix to production and I like to keep this option open if need be.  If you are strongly opposed to this idea, please, by all means, don’t check the box.

image

The next tab is boring.  I don’t like to deploy a crazy number of DLLs so I merge all outputs to a single assembly.  Again, you may have another option and feel free to change this selection if you so wish.

image

If you follow my lead, take care when choosing a single assembly name.  The Assembly Name can not be the same as the website or any other project in your solution otherwise you’ll receive a circular reference build error.  In other words, I can’t name the assembly MvcApplication293 or my output window would start yelling at me.

image

Remember when we called out our QA configuration files?  Click on the Deployment tab and you’ll see how where going to use them.  Notice the Web.config file section replacements value.  All this does is swap called out web.config sections with the content of the Config\QA\* files.  You can reduce or extend this list as you deem fit. 

image

Did you see the “Use external configuration source file” option?  You know how you can point any of your web.config sections to an external file via the configSource attribute?  This option allows you to leverage that technique and instead of replacing the content of the sections, you will replace the configSource attribute value instead.

  1. <appSettings configSource="Config\QA\AppSettings.config" />

Go ahead and Apply your changes.  I’d like to take a look at the project file we just updated.  Right-click on the Web Deployment Project and select “Open Project File.”

image

One of the first configuration blocks reflects core Release build settings.  There are a couple of points I’d like to call out here:

  • DebugSymbols=false ensures the compilation debug attribute in your web.config is flipped to false as part of build process.  There’s some crumby (more likely old) documentation which implies you need a ToggleDebugCompilation task to make this happen.  Nope. Just make sure the DebugSymbols is set to false. 

  • EnableUpdateable implies a single dll for the web application rather than a dll for each object and and empty view file. I think updatable applications are cleaner and include the benefit (or risk based on your perspective) that portions of the application can be updated directly on the server.  I called this out earlier but I wanted to reiterate.

  1. <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
  2.     <DebugSymbols>false</DebugSymbols>
  3.     <OutputPath>.\Release</OutputPath>
  4.     <EnableUpdateable>true</EnableUpdateable>
  5.     <UseMerge>true</UseMerge>
  6.     <SingleAssemblyName>MvcApplication293</SingleAssemblyName>
  7.     <DeleteAppCodeCompiledFiles>true</DeleteAppCodeCompiledFiles>
  8.     <UseWebConfigReplacement>true</UseWebConfigReplacement>
  9.     <ValidateWebConfigReplacement>true</ValidateWebConfigReplacement>
  10.     <DeleteAppDataFolder>true</DeleteAppDataFolder>
  11.   </PropertyGroup>

The next section is self-explanatory.  The content merely reflects the replacement value you provided via the Property Pages.

  1. <ItemGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
  2.     <WebConfigReplacementFiles Include="Config\QA\AppSettings.config">
  3.       <Section>appSettings</Section>
  4.     </WebConfigReplacementFiles>
  5.     <WebConfigReplacementFiles Include="Config\QA\Db.config">
  6.       <Section>connectionStrings</Section>
  7.     </WebConfigReplacementFiles>
  8.     <WebConfigReplacementFiles Include="Config\QA\SmtpSettings.config">
  9.       <Section>system.net/mailSettings/smtp</Section>
  10.     </WebConfigReplacementFiles>
  11.   </ItemGroup>

You’ll want to extend the ItemGroup section to include the files you wish to exclude from the build.  The sample ExcludeFromBuild nodes exclude all obj, svn, csproj, user, pdb artifacts from the build. Enough though they files aren’t included in your web project, you’ll need to exclude them or they’ll show up along with required deployment artifacts. 

  1. <ItemGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
  2.     <WebConfigReplacementFiles Include="Config\QA\AppSettings.config">
  3.       <Section>appSettings</Section>
  4.     </WebConfigReplacementFiles>
  5.     <WebConfigReplacementFiles Include="Config\QA\Db.config">
  6.       <Section>connectionStrings</Section>
  7.     </WebConfigReplacementFiles>
  8.     <WebConfigReplacementFiles Include="Config\QA\SmtpSettings.config">
  9.       <Section>system.net/mailSettings/smtp</Section>
  10.     </WebConfigReplacementFiles>
  11.     <ExcludeFromBuild Include="$(SourceWebPhysicalPath)\obj\**\*.*" />
  12.     <ExcludeFromBuild Include="$(SourceWebPhysicalPath)\**\.svn\**\*.*" />
  13.     <ExcludeFromBuild Include="$(SourceWebPhysicalPath)\**\.svn\**\*" />
  14.     <ExcludeFromBuild Include="$(SourceWebPhysicalPath)\**\*.csproj" />
  15.     <ExcludeFromBuild Include="$(SourceWebPhysicalPath)\**\*.user" />
  16.     <ExcludeFromBuild Include="$(SourceWebPhysicalPath)\bin\*.pdb" />
  17.     <ExcludeFromBuild Include="$(SourceWebPhysicalPath)\Notes.txt" />
  18.   </ItemGroup>

Pre/post build and Pre/post merge tasks are added to the final code block.  By default, your project file should look like the following – a completely commented out section.

  1. <!– To modify your build process, add your task inside one of
  2.        the targets below and uncomment it. Other similar extension
  3.        points exist, see Microsoft.WebDeployment.targets.
  4.   <Target Name="BeforeBuild">
  5.   </Target>
  6.   <Target Name="BeforeMerge">
  7.   </Target>
  8.   <Target Name="AfterMerge">
  9.   </Target>
  10.   <Target Name="AfterBuild">
  11.   </Target>
  12.   –>

Update the section to remove all temporary Config folders and files after the build. 

  1. <!– To modify your build process, add your task inside one of
  2.        the targets below and uncomment it. Other similar extension
  3.        points exist, see Microsoft.WebDeployment.targets.  
  4.   <Target Name="BeforeMerge">
  5.   </Target>
  6.   <Target Name="AfterMerge">
  7.   </Target>  
  8.   <Target Name="BeforeBuild">   
  9.   </Target>
  10.       –>
  11.   <Target Name="AfterBuild">
  12.     <!– WebConfigReplacement requires the Config files. Remove after build. –>
  13.     <RemoveDir Directories="$(OutputPath)\Config" />
  14.   </Target>

That’s it for setup.  Save the project file, flip the solution to Release Mode and build.  If there’s an issue, consult the Output window for details.  If all went well, you will find your deployment artifacts in your Web Deployment Project folder like so.

image

Both the code source and published application will be there. Inside the Release folder you will find your “published files” and you’ll notice the Config folder is no where to be found.  In the Source folder, all project files are found with the exception of the items which were excluded from the build.

I’ll wrap up this tutorial by calling out a little Web Deployment pet peeve of mine: there doesn’t appear to be a way to add an existing web deployment project to a solution.  The best I can come up with is create a new web deployment project and then copy and paste the contents of the existing project file into the new project file.  It’s not a big deal but it bugs me.

© Johnny Coder or respective owner

Related posts about ASP.NET

Related posts about ASP.NET MVC