Deploy ASP.NET Web Applications with Web Deployment Projects

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="sender@application.com">
  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="qasender@application.com">
  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.

Comments

  1. Hwo do we precompile the aspx mark-ups using the web deployment project for a VS 2008 Web Application Project?

  2. Hi Ram,

    I think I know what you’re after. Right-click on your web deployment project and select the Property Pages. Under the Output Assemblies section, you’ll want to select the first option — Merge all outputs to a single assembly — and provide an Assembly name. I think that should do it for you.

    Best of luck,
    Ben

  3. Good question, Rick. Other than ensuring the XML is well formatted, I don’t think there are any debugging tricks. The same goes for test project configuration. Test runners sometimes simply bomb without explanation if the configuration is bad. If you come up with something, please let me know.

  4. The way we deploy project is copy whole project to QA and delete .vb files.
    Is this right way to do.

  5. After creating my Web Deployment Project, Now I need to move my compiled website to a (external) production server whose URL is: http://kuloba.com. My application will be in folder: “kamakye”. So the URL of my application will be: http://kuloba.com/kamakye/Login.aspx. Which files of my Web Deployment project do i have to copy in which folder. Also note that the server http://kuloba.com may have other web applications running there.

  6. Hi,
    How do we take care for App Web references? I’ve a REST web service & this web service calls another web service & I added web reference to this web service. Now, this web reference is different for Beta & Production environment. How do we handle this here?

    Thanks!

  7. is the output will be in a form of MSI? otherwise how can Technical service guys install this application

  8. I would like to express my appreciation to the writer for bailing me out of this particular problem. Just after looking out through the the net and seeing opinions that were not productive, I believed my life was well over. Being alive without the strategies to the issues you have fixed by way of your main article is a critical case, and the kind which may have in a wrong way affected my career if I hadn’t discovered the website. Your main talents and kindness in dealing with all areas was invaluable. I’m not sure what I would’ve done if I hadn’t come upon such a point like this. I am able to at this point look forward to my future. Thanks so much for this skilled and sensible help. I will not think twice to refer your web blog to any person who needs to have guidelines about this problem.

  9. I absolutely love your blog and find a lot of your post’s to be precisely what I’m looking for. can you offer guest writers to write content in your case? I wouldn’t mind writing a post or elaborating on most of the subjects you write in relation to here. Again, awesome web log!

  10. Do I have to manually copy the compiled files to the web server I wish to deploy the production version of the site to? Is there any way to automate that or is it a manual copy every time?

closed