Posts tagged ‘visual studio’

Excluding files from Visual Studio web deployment

The other day at work, I was fine tuning the deployment process for one of our internal web sites.  One of the issues we had were a set of assemblies that were referenced by the web project but which needed to be excluded from deployment.

The process of excluding files is very simple, but requires some knowledge of how publishing in VS works.  I’m using VS2012 with Update 2 installed, though this feature might have been added before that.

Step 1: During File Preview, determine the list of files you want to exclude

For this exercise, I’ll exclude the following files:

FilesToExcludeFromPublish

Step 2: Modify the .pubxml

The edit to you publish profiles is very easy: just set the ExcludeFilesFromDeployment property.  In my publish profile (the .pubxml file), I added the following lines within the PropertyGroup:

    <ExcludeFilesFromDeployment>
      ExcludeThisFile.aspx;DoNotDeploy.aspx
    </ExcludeFilesFromDeployment>

Note that you can also use wildcards here if your file names are patterned.

There was also previously a property called ExcludeFilesFromPackage, but I prefer ExcludeFilesFromDeployment as it clarifies that this is not limited to just using WebDeploy packages.

Step 3: Verify that the files are excluded

Now when I do the file Preview again, I see that those files are no longer shown in the list (note: I haven’t actually published any files yet)

image

When I publish, the files are also not included:

image

It’s that easy!

The differences between Solution build configurations and Project build configurations

In VS2012 RC, there is a bug in the Web Publishing feature for WAPs: when a solution build configuration doesn’t match the project build configuration, VS doesn’t correctly find the set of files to be published.  Did that make sense to you?  If so, you’re probably not interested in the rest of this post.  Otherwise, keep reading, and hopefully you’ll learn something new and (remotely) useful.

Project Build Configurations

Each project has 2 parts to it’s build configuration: the platform, which is any of x86/x64/Any CPU; and the configuration, which defaults to one of Debug or Release, but you can create your own with whatever name you’d prefer.

Within the project file, you can specify certain project properties based on the active build configuration.  For example, in the project file, there are several sections defined as follows:

  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <!-- snip -->
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <!-- snip -->
  </PropertyGroup>

With these different settings (configuration/platform), you can tweak the behavior of your project build to suit different environments.  In the example cited above, you can affect the debug symbols or compiler optimizations applied during build.

Solution Build Configurations

The solution build configuration doesn’t actually affect any property values during build.  Instead, it’s basically just a mapping of each project with its project build configuration.  For example, here’s the contents of a solution file which contains two projects, has two configurations defined (Debug/Release) and two platforms defined (Any CPU/x64):

	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{0595D46B-8467-42BB-BFB5-F7B38EEA96E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{0595D46B-8467-42BB-BFB5-F7B38EEA96E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{0595D46B-8467-42BB-BFB5-F7B38EEA96E5}.Debug|x64.ActiveCfg = Debug|Any CPU
		{0595D46B-8467-42BB-BFB5-F7B38EEA96E5}.Debug|x64.Build.0 = Debug|Any CPU
		{0595D46B-8467-42BB-BFB5-F7B38EEA96E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{0595D46B-8467-42BB-BFB5-F7B38EEA96E5}.Release|Any CPU.Build.0 = Release|Any CPU
		{0595D46B-8467-42BB-BFB5-F7B38EEA96E5}.Release|x64.ActiveCfg = Release|Any CPU
		{0595D46B-8467-42BB-BFB5-F7B38EEA96E5}.Release|x64.Build.0 = Release|Any CPU
		{F564EBE0-B6EB-4277-BC60-15E093B1A3E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{F564EBE0-B6EB-4277-BC60-15E093B1A3E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{F564EBE0-B6EB-4277-BC60-15E093B1A3E5}.Debug|x64.ActiveCfg = Debug|Any CPU
		{F564EBE0-B6EB-4277-BC60-15E093B1A3E5}.Debug|x64.Build.0 = Debug|Any CPU
		{F564EBE0-B6EB-4277-BC60-15E093B1A3E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{F564EBE0-B6EB-4277-BC60-15E093B1A3E5}.Release|Any CPU.Build.0 = Release|Any CPU
		{F564EBE0-B6EB-4277-BC60-15E093B1A3E5}.Release|x64.ActiveCfg = Release|Any CPU
	EndGlobalSection

This is unintuitive at best, so I’ll explain how it works.

The GUIDs each represent one of the projects in the solution.  You can find out which maps to which towards the top of the solution file (that one’s easy enough, since you’re just looking for a match, that I won’t bother to explain it).

Following the GUID is the solution configuration.  So, {GUID}.Debug|x64 means that the active solution configuration is Debug/x64. 

Next comes some project specific properties.  First we see ActiveCfg, which is telling us the active configuration for that project, when the solution configuration is configured as shown.  We can see that when the Solution Configuration is set to Debug|x64, both projects are actually using Debug|Any CPU.  This is often a source of confusion between Solution and Project configurations – they aren’t necessarily the same!

The other property we see is Build.0, which indicates whether the project is included to be built in this solution configuration.  If you notice, for Release|x64, the project GUID starting with F564EBE0 doesn’t have a Build.0 value.  This means that the project is not included in build when the solution is set to Release|x64.

All of these settings can be configured in VS through the Configuration Manager.  For example, here’s a snapshot showing the Release|x64 configuration above, with one project left out of the build:

Configuration Manager

What we’ve learned

From the examples above, I hope it’s now clear what the different roles of Project Configuration and Solution Configuration play in managing your solution’s build process.  We saw that the Project Configuration allowed us to customize the build behavior for specific projects.  The Solution Configuration allows us to configure a batch of projects with their own specific configurations in a single build (for example, if I always wanted to build ClassLibrary1 with Debug settings, I can set that in the Solution’s Release configuration).

A better way to compile your views in ASP.NET MVC

Many people are aware of and use the MvcBuildViews property that was added to MVC in the version 1 Release Candidate.  This property enabled a build target to call the aspnet_compiler.exe when the build was complete.  However, when using this in conjunction with the One Click Web Publishing in Visual Studio, you may get errors about certain properties in web.config not being allowed:

It is an error to use a section registered as allowDefinition='MachineToApplication' beyond application level.  This error can be caused by a virtual directory not being configured as an application in IIS.

In simple English, this is just stating that the precompiler found properties in Web.config that can only be allowed in the web.config file at the root of your project.  What’s odd is that if you double click the error, which takes you to the offending property, it will open up what looks your web.config file.  What’s not obvious is that it’s actually opening a separate copy of web.config which exists somewhere under the obj directory in your project:

file path to erroneous web.config file

In fact, if you look carefully, you’ll see that any web.config transforms that apply during publishing will be applied to this file already.

There are a number of workarounds floating around the Internet today, such as always doing a Clean before a Build or deleting the obj folder.  There’s also the option of changing the $(BaseIntermediateOutputDirectory) in the project file so that it is no longer under the project root.  However, each of these is an annoyance to put into place.

As part of the publishing improvements made in VS 2012, there is now built-in support for the ASP.NET precompilation and merge tools for all Web Application Projects, which includes MVC.  (Side note: Web Site Projects have long supported precompilation but not merge through the Publish command).  This new feature, carried in from Web Deployment Projects, now lives on the Package/Publish Web tab of the project properties:

Precompile options for project

When you use this feature, which only applies at publish time instead of build, Visual Studio is smart enough to avoid the contents of the obj directory.  In fact, it’s also smart enough to only compile the files that are included in your project, which is another small issue with MvcBuildViews.  With the Advanced options, you can even configure more specific behaviors, including merging your precompiled assemblies, or whether to compile your markup files (make the site not “updateable”):

Advanced precompilation settings

The one catch with this is that the publish settings are configured on a per build configuration basis.  In the screenshot above, the setting only applies to the Debug configuration.  If you’re publishing with Release (which is now the default in VS2012, instead of whatever is active in VS), then make sure to configure it for that build configuration.

Also worth noting for people still on VS2010: there now is an out-of-band release for Visual Studio 2010 and Visual Web Developer 2010 which gives you the same new publish features as VS2012.  This allows you to use the same new pre-compilation feature for any Web Application Projects as well.  To get the VS2010 update, you can visit the Azure developer tools download page.