Note: I’d like to thank Tom Dykstra for helping me put this together
Overview
In this tutorial you'll see how to use a web deployment package package to deploy an application. A deployment package is a .zip file that includes all of the content and metadata that's required to deploy an application.
Deployment packages are often used in enterprise environments. This is because a developer or a continuous integration server can create the package without needing to know things like passwords that are stored in Web.config files. Only the server administrator who actually installs the package needs to know those passwords, and that person can enter the details at installation time.
In a smaller organization that doesn't have separate people for these roles, there's less need for deployment packages. But you can also use deployment packages as a way to back up and restore the state of an application. After you use a deployment package to deploy, you can save the package,. Then if a subsequent deployment has a problem, you can quickly and easily restore the application state to the earlier state by reinstalling the earlier package. (This scenario is more complicated if database changes are involved, however.)
This tutorial shows how to use Visual Studio to create a package and IIS Manager to install it. For information about how to create and install packages using the command line, see ASP.NET Deployment Content Map on the MSDN web site.
To keep things relatively simple, this example assumes you have already deployed the application and its databases, and you only need to deploy a code update. You have made the code update, and you are ready to deploy it first to your test environment (IIS on your local computer) and then to your hosting provider. You have a Test build configuration that you use for the test environment and you use the Release build configuration for the production environment. In the example, the name of the Visual Studio project is ContosoUniversity, and instructions for its initial deployment can be found in a series of tutorials that will be published in December on the ASP.NET web site.
The hosting provider shown, Cytanium.com, is one of many that are available, and its use here does not constitute an endorsement or recommendation.
Note The following example uses separate packages for the test and production environments, but you can also create a single deployment package that can be used for both environments. This would require that you use Web Deploy parameters instead of Web.config transformations for Web.config file changes that depend on deployment destination. For information about how to use Web Deploy parameters, see How to: Use Parameters to Configure Deployment Settings When a Package is Installed.
Configuring the Deployment Package
In this section, you'll configure settings for the deployment package. Some of these settings are the same ones that you set also for one-click publish, others are only for deployment packages.
Open the Package/Publish Web tab of the Project Properties window and select the Test build configuration.
For this deployment you aren't making any database changes, so clear Include all databases configured in Package/Publish SQL tab. Make sure Exclude files from the App_Data folder is selected.
Review the settings in the section labeled Web Deployment Package Settings:
By default, deployment packages are created as .zip files. You don't need to change this setting.
By default, deployment packages are created in the project's obj\Test\Package folder. You don't need to change this setting.
The default IIS web application name is the name of the project with "_deploy" appended to it. Remove that suffix. You want the application to be named just ContosoUniversity in IIS on your computer.
For this tutorial you're not deploying IIS settings, so you don't need to enter a password for that.
The Package/Publish Web tab now looks like this:
You also need to configure settings for deploying to the production environment. Select the Release build configuration to do that.
Change IIS Web site/application name to use on the destination server to a string that will serve as a reminder of what you need to do later when this value is displayed in the IIS Manager UI: "[clear this field]". The text box on this page won't stay cleared even if you clear it, so entering this note to yourself will remind you to clear this value later when you deploy. When you deploy to your hosting provider, you will connect to a site, not to a server, and in this case you want to deploy to the root of the site.
Creating a Deployment Package for the Test Environment
To create a deployment package, first make sure you've selected the right build configuration. In the Solution Configurations drop-down box, select Test.
In Solution Explorer, right-click the project that you want to build the package for and then select Build Deployment Package.
The Output window reports successful a build and publish (package creation) and tells you where the package was created.
Installing the Deployment Package in the Test Environment
The next step is to install the deployment package in IIS on your development computer.
Run IIS Manager. In the Connections pane of the IIS Manager window, expand the local server node, expand the Sites node, and select Default Web Site. Then in the Actions pane, click Import Application. (If you don't see an Import Application link, the most likely reason is that you have not installed Web Deploy. You can use the Web Platform Installer to install both IIS and Web Deploy.)
In the Select the Package wizard step, navigate to the location of the package you just created. By default, that's the obj\Test\Package folder in your ContosoUniversity project folder. (A package created with the Release build configuration would be in obj\Release\Package.)
Click Next. The Select the Contents of the Package step is displayed.
Click Next.
The step that allows you to enter parameter values is displayed. The Application Path value defaults to "ContosoUniversity", because that's what you entered on the Package/Publish Web tab of the Project Properties window.
Click Next.
The wizard asks if you want to delete files at the destination that aren't in the source.
In this case you haven't deleted any files that you want to delete at the destination, so the default (no deletions) is okay. Click Next.
IIS Manager installs the package and reports its status.
The process for deploying to production is similar except that you create the package using the Release build configuration, and you install it in IIS Manager using a remote connection to the hosting provider. But first you have to install the IIS Manager feature that facilitates remote connections.
Click the following link to use the Web Platform Installer for this task:
After you install the IIS Manager for Remote Administration, run IIS Manager. You see a new Start Page in IIS Manager that has several Connect to ... links in a Connection tasks box. (These options are also available from the File menu.)
In IIS Manager, click Connect to a site. In the Specify Site Connection Details step, enter the Server name and Site name values that are assigned to you by your provider, and then click Next. For a hosting account at Cytanium.com, you get the server name from Service URL in the Visual Studio 2010 section of the welcome email. The site name is indicated by "Site/application" in the same section of the email.
In the Provide Credentials step, enter the user name and password assigned by the provider, and then click Next:
You might see a Server Certificate Alert dialog box. If you're sure that you've entered the correct server and site name, click Connect.
In the Specify a Connection Name step, click Finish.
After IIS Manager connects to the provider's server, a New Feature Available dialog box might appear that lists administration features available for download. Click Cancel — you've already installed everything you need for this deployment.
After the New Feature Available box closes, the IIS Manager window appears. There's now a node in the Connections pane for the site at the hosting provider.
Creating a Package for the Production Site
The next step is to create a deployment package for the production environment. In the Visual Studio Solution Configurations drop-down box, select the Release build configuration.
In Solution Explorer, right-click the ContosoUniversity project and then select Build Deployment Package.
The Output window reports a successful build and publish (package creation), and it tells you that the package is created in the obj\Release\Package folder in your project folder.
Installing the Package in the Production Environment
Now you can install the package in the production environment. In the IIS ManagerConnections pane, select the new connection you added earlier. Then click Import Application, which will walk you through the same process you followed earlier when you deployed to the test environment.
In the Select the Package step, select the package that you just created:
In the Select the Contents of the Package step, leave all the check boxes selected and click Next:
In the Enter Application Package Information step, clear the Application Path and click Next:
The wizard asks if you want to delete files at the destination that aren't in the source.
You don't need to have anything deleted, so just click Next.
When you get the warning about installing to the root folder, click OK:
Package installation begins. When it's done, the Installation Progress and Summary dialog box is shown:
Click Finish. Your application has been deployed to the hosting provider's server, and you can test by browsing to your public site's URL.
You've now seen how to deploy an application update by manually creating and installing a deployment package. For information about how to create and install packages from the command line in order to be able to integrate them into a continuous integration process, see the ASP.NET Deployment Content Map on the MSDN web site.
Note: I’d like to thank Tom Dykstra for helping me put this together
As part of the deployment process you might need to set permissions on one or more folders in the destination web application. For example, if your application allows users to upload files, it needs write access to a folder in order to store the uploaded files. By default, theweb publishing pipeline (the automated deployment process) automatically sets write permission on the App_Data folder in order to enable database updates in case you store databases in that folder, and you can use the same method to make the deployment process automatically set permissions on any folder you choose.
The <projectname>.wpp.targets File
The web publishing pipeline is controlled by MSBuild .targets files that are installed with Visual Studio. Rather than editing the Visual Studio .targets files, you can create a project-specific .targets file that Visual Studio will use to modify the deployment process for a specific project. To do that, you create an XML file in the project folder and name it < projectname>.wpp.targets. The following example shows XML markup that causes the web publishing pipeline to set write permissions for a folder named Elmah located in the root folder of the application. The sample is designed to work for both deployment methods: publish or web deployment package.
The first Target element ("SetupCustomAcls") causes a setAcl action to be added to the deployment package's source manifest when the package is created. The source manifest is a file that specifies what to include in the deployment package. The path to the folder is specified using an MSBuild variable (_MSDeployDirPath_FullPath) that specifies the path to the project root folder:
This isn't all you need to do, however, because the permissions actually need to be set on the folder in the destination application, not the folder in the deployment package. That's why the second Target element is needed. The second Target element ("DeclareCustomParameters") creates a user-defined Web Deploy parameter named ElmahSetAclParam. The value of this parameter will change the value of the setAcl path at deploy time. TheDefaultValue element of the ElmahSetAclParam parameter sets the value that will be used when you are deploying by creating and installing a deployment package; the Value element sets the value that will be used when you are publishing without using a deployment package.
If you are using a deployment package, the actual path to the destination folder isn't known until the package is installed. Therefore the default value of this parameter is set using an MSDeploy parameter that resolves to the name of a system-defined Web Deploy parameter:
When the package is created, _MsDeployParameterNameForContentPath is translated into "{IIS Web Application Name}", so the actual default value becomes "{IIS Web Application Name}/Elmah". When the package is installed, the value of that Web Deploy parameter is the path of the destination root folder, and so as a result the ElmahSetAclParam parameter resolves to the physical path of the destination Elmah folder (for example: C:\inetpub\wwwroot\ContosoUniversity\Elmah). That path then replaces the package's physical path for the Elmah setAcl element in the source manifest.
When you publish the project rather than using a deployment package, the Value element instead of the DefaultValue element provides the value for the ElmahSetAclParam parameter. In that case, you are deploying from Visual Studio, and Visual Studio has the actual destination path value in an MSBuild property, so the Value element can specify that MSBuild property directly and does not need to use a Web Deploy variable:
<Value>$(_DestinationContentPath)/Elmah</Value>
The "Hidden" value in the Tags element prevents the ElmahSetAclParam parameter from being displayed in the IIS Manager UI if you use IIS Manager to install the package. The UI doesn't have to show the value, because a user never needs to change it manually.
<Tags>Hidden</Tags>
Adding More Folders
You can add more folders by adding ItemGroup elements. The following example builds on the earlier one by also granting Read permission for the bin folder to the NETWORK SERVICE account. (This is required in some cases for SQL Server Compact.) Notice that in order to specify the account to which access is granted, "setAclUser" was added to the < AdditionalProviderSettings> element, and a <SetAclUser> element specifying NETWORK SERVICE was added.
Setting up .targets files is like writing code -- rarely do you get everything right the first time. If you do make a mistake that you have to fix, you should be aware that Visual Studio caches target files. This means that every time you change a .targets file, you must exit Visual Studio and restart it before you rebuild the package in order to see the effect of your change. This is not an issue if you create packages using the command line.
Making Changes that Affect Parameters in Packages
Visual Studio will not rebuild a package if it cannot determine that a change has been made, and changes that affect Web Deploy parameters are sometimes not recognized as changes. Therefore, if you make any changes that affect parameters in the source manifest, it's best to select Clean Solution from the Build menu in order to delete the contents of the Package folder before you rebuild the package.
When I talk to people about the XDT (web.config) transforms that web projects support for package/publish one of the most common questions is “Does this work for non-web projects?” Unfortunately the answer is No, but myself and a friend of mine (Chuck England) have created a Visual Studio add in which enables just this. You can find it in the Visual Studio gallery under the name SlowCheetah – XML Transforms. Here is an overview of the features of the add in.
Add tooling to desktop project to create XDT transforms
Transform app.config for desktop projects based on build configuration
Transform any XML file to the output folder base on build configuration
Add tooling to enable previewing XDT transforms
For web projects easily transform other XML files during package/publish
After you install the add in you will get the following menu item when you right click any XML file.
For each build configuration defined you will get a transform created as a child item.
These files are stub XDT transforms. You can place your transform content in those files and they will be executed when you debug/run your application. For example if your app.config contained the following.
You are not limited to transforming app.config, you can transform any XML file. When you create a transform for an arbitrary XML file when you run your application the transformed XML file will be dropped into the output (bin) folder of your application.
Previewing Transforms
You can easily preview transform results as well. After you have created the transform file you can right click on it and select Preview Transform.
After you click it you should see the following.
I hope you guys find this useful. Let me know if you have any feedback on this!
Note: This add in was created by me and a friend of mine, these are not created nor supported by Microsoft.
Today someone sent me an email asking how to call the System.Environment.GetFolderPath method passing in the value of MyDocuments for the value of the folder parameter. I was expecting the below to do the trick.
To my surprise I was faced with the following error.
Build started 3/20/2011 6:20:36 PM.
Project "C:\temp\_NET\msbuild\PropFunction01.proj" on node 1 (default targets).
C:\temp\_NET\msbuild\PropFunction01.proj(20,5): error MSB4186: Invalid static method invocation syntax: "[System.Environment]::GetFolderPath(System.Environment.Spec ialFolder.MyDocuments)". Requested value 'System.Environment.MyDocuments' was not found. Static method invocation should be of the form: $([FullTypeName]::Method()), e.g. $([System.IO.Path]::Combine(`a`, `b`)).
Done Building Project "C:\temp\_NET\msbuild\PropFunction01.proj" (default targets) -- FAILED.
Build FAILED.
So I sent an email to the MSBuild team asking “WTF why doesn’t this work?!”, and Dan Moseley (a lead dev there) sent me a snippet that worked, its below.
In that snippet instead of using the fully qualified class name of System.Environment.SpecialFolder.MyDocuments, for some reason you have to use the shortened name of just SpecialFolder.MyDocuments. It seems like a bug to me, but at least there is a work around!
Today I saw a post on stackoverflow.com asking Using Microsoft AJAX Minifier with Visual Studio 2010 1-click publish. This is a response to that question. The Web Publishing Pipeline is pretty extensive so it is easy for us to hook in to it in order to perform operation such as these. One of those extension points, as we’ve blogged about before, is creating a .wpp.targets file. If you create a file in the same directory of your project with the name {ProjectName}.wpp.targets then that file will automatically be imported and included in the build/publish process. This makes it easy to edit your build/publish process without always having to edit the project file itself. I will use this technique to demonstrate how to compress the CSS & JavaScript files a project contains before it is published/packaged.
Eventhough the question specifically states Microsoft AJAX Minifier I decided to use the compressor contained in Packer.NET (link in resources section). I did this because when I looked at the MSBuild task for the AJAX Minifier it didn’t look like I could control the output location of the compressed files. Instead it would simply write to the same folder with an extension like .min.cs or .min.js. In any case, when you publish/package your Web Application Project (WAP) the files are copied to a temporary location before the publish/package occurs. The default value for this location is obj\{Configuration}\Package\PackageTmp\ where {Configuration} is the build configuration that you are currently using for your WAP. So what we need to do is to allow the WPP to copy all the files to that location and then after that we can compress the CSS and JavaScript that goes in that folder. The target which copies the files to that location is CopyAllFilesToSingleFolderForPackage. (To learn more about these targets take a look at the file %Program Files (x86)%\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets.) To make our target run after this target we can use the MSBuild AfterTargets attribute. The project that I created to demonstrate this is called CompressBeforePublish, because of that I create a new file named CompressBeforePublish.wpp.targets to contain my changes.
Here I’ve created one target, CompressJsAndCss, and I have included AfterTargets=”CopyAllFilesToSingleFolderForPackage” which causes it to be executed after CopyAllFilesToSingleFolderForPackage. Inside this target I do two things, gather the files which need to be compressed and then I compress them.
Here I use an item list for both JavaScript files as well as CSS files. Notice that I am using the _PackageTempDir property to pickup .js & .css files inside the temporary folder where the files are written to be packaged. The reason that I’m doing that instead of picking up source files is because my build may be outputting other .js & .css files and which are going to be published. Note: since the property _PackageTempDir starts with an underscore it is not guaranteed to behave (or even exist) in future versions.
2. Compress files
I use the Packer task to compress the .js and .css files. For both sets of files the usage is pretty similar so I will only look at the first usage.
Here the task is fed all the .js files for compression. Take a note how I passed the files into the task using, %(_JavaScriptFiles.Identity), in this case what that does is to cause this task to be executed once per .js file. The %(abc.def) syntax invokes batching, if you are not familiar with batching please see below. For the value of the output file I use the _PackageTempDir property again. In this case since the item already resides there I could have simplified that to be @(_JavaScriptFiles->’%(FullPath)’) but I thought you might find that expression helpful in the case that you are compressing files which do not already exist in the _PackageTempDir folder.
Now that we have added this target to the .wpp.targets file we can publish/package our web project and it the contained .js & .css files will be compressed. Note: Whenever you modify the .wpp.targets file you will have to unload/reload the web project so that the changes are picked up, Visual Studio caches your projects.
In the image below you can see the difference that compressing these files made.
You can download the entire project below, as well as take a look at some other resources that I have that you might be interested in.
Back in November I participated in Virtual Tech Days which is an online conference presented by Microsoft. In the session I discussed the enhancements to web deployment using Visual Studio 2010 and MSDeploy. Some of the topics which I covered includ:
web.conig (XDT) transforms
How to publish to local file system using Visual Studio
How to publish to a 3rd party host using Visual Studio via MSDeploy
How to publish to local IIS server using the .cmd file generated by Visual Studio
How to use msdeploy.exe to delete IIS applications
How to use the IIS Manager to import web packages
How to use msdeploy.exe to deploy a web package to the local IIS server
How to use msdeploy.exe to deploy a web package to a remove IIS server
How to use msdeploy.exe to deploy a web package & set parameters using SetParameters.xml to a remote IIS server
You can download the video & all of my sample files at http://virtualtechdays.com/pastevents_2010november.aspx. In the samples you will find all of the scripts that I used and a bunch of others which I didn’t have time to cover. Enjoy!
A few days ago Jason Zander blogged about the availability of Visual Studio SP1 Beta (all links below in resources section). I am happy to let you guys know that with SP1 Beta we have enabled integration of IIS Express into Visual Studio. After you have installed SP1 Beta you have to download IIS Express separately for the option to “light up”. After you’ve downloaded and installed IIS Express you can now create Web projects and Websites which use IIS Express instead of Cassini (the default web server used in Visual Studio). For more information regarding the difference between IIS Express and IIS/Cassini please see Scott’s blog linked below. Visual Studio 2010 has two types of web projects; Web Application Project (WAP) and Website projects. You can use either project type with IIS Express.
Enabling IIS Express for web projects
For both WAP and Website projects which were using Cassini we have a very simply method for you to use IIS Express. You can just right click then select the context menu option “Use IIS Express”. Take a look at the screen shot that follows for that command.
After you do this your project will use IIS Express instead of Cassini going forward. If you wish to revert back to using Cassini you can just right click on the project and select “Use Visual Studio Development Server…” You can also make IIS Express your default web server for new projects as well.
For Web site projects when you create a new site you can create it such that IIS Express hosts it instead of Cassini. From Visual Studio when you select File->New-> Web Site you will see the New Web Site dialog. On that dialog you can click on the Browse button (see image below).
After you click that you will be prompted to enter the location where the site will be located. From there you can select “Local IIS” and the create a new IIS Express site for it.
In this dialog you need to select IIS Express Sites then click on the Create New Site button located towards the upper right hand corner. Once you do this it will create a new IIS Express site for your Web site.
Making IIS Express your default web server
In order to make IIS Express for new file based web projects you can go to the menu option Tools->Options->Projects and Solutions->Web Projects and check the “Use IIS Express for new file-based web sites and projects” check box. You can see this option in the next image.
After you have done this new projects/sites will use IIS Express by default. Note: if you have any existing projects/sites you will still have to “opt-in” to using IIS Express for each project.
Using IIS Express
After you have enabled IIS Express to be your projects web server, when you start debugging, or just start running your app, from Visual Studio you will see a new system tray icon appear (). You can right click on this icon to to quickly see what applications it is hosting. Each hosted application will have its own context menu. From this menu you can browse out to the application as well as stop it quickly.
You can also click on “Show All Applications” to open a dialog which give you more information about the sites that IIS Express is hosting. For example I opened this dialog and selected a running application and the result is shown in the image below.
There are a few notable values here
The URL for each hosted application
The Runtime version for the application
The path to the application
The path to the applicationHost.config file
The default location for the applicationHost.config file is your users’ directory. This enables IIS Express to run without requiring admin privileges. As you may know IIS (i.e. the full IIS) uses the applicationHost.config file to store its configuration. IIS Express is similar to IIS in that it uses a file also named applicationHost.config (not the same file as IIS though). The file that IIS uses is stored under the System32 directory and is shared across all users. The IIS Express config is specific to the current user. Regarding the runtime version, this is the version of the CLR which your application pool will use. For IIS Express application pools will, by default, use CLR 4.0. You can change this default in the applicationHost.config file for IIS Express. Visual Studio will assign the correct CLR version to your app pool based on the target framework version.
You can customize a few options for your site directly from Visual Studio. If you select your web project/site in the Solution Explorer and then open the Properties pane (you can right-click and select Properties on the project/site if it is not visible) you should see something similar to the following.
These settings will change how IIS Express hosts your site. One of the missing features of Cassini was the ability to host SSL sites. In IIS Express you can enable this. For example for this site I changed the value for SSL Enabled to be True, then a new URL was assigned so that I can use SSL to browse to the site. Please note that IIS Express will install a self-signed cert and you will see the following security warning from Internet Explorer when you browse to an https URL hosted by IIS Express.
One thing to make a note of is that when you change the settings for IIS Express here these settings are stored in the applicationHost.config file for IIS Express and not with the project/site itself. So if you are working in a team then your other team members will have to make the same changes. If you want to edit a setting which is not shown on the properties grid then you can edit the applicationHost.config file directly. You can easily open this file by clicking on the applicationHost.config link in the IIS Express dialog shown previously. For WAP projects you can change the port that is used from the Web tab in the project properties page.
Known issues
There are currently some known issues with IIS Express which are listed below. If you run into any more please let us know.
Profiling is not supported
If you add a Web Deployment Project (WDP) to an IIS Express web site you will have to remove the ‘:’ from the name of the WDP
Some issues using WDP for IIS Express sites with sub-webs
A few days ago Jason Zander blogged about the availability of Visual Studio SP1 Beta (all links below in resources section). I am happy to let you guys know that with SP1 Beta we have enabled integration of IIS Express into Visual Studio. After you have installed SP1 Beta you have to download IIS Express separately for the option to “light up”. After you’ve downloaded and installed IIS Express you can now create Web projects and Websites which use IIS Express instead of Cassini (the default web server used in Visual Studio). For more information regarding the difference between IIS Express and IIS/Cassini please see Scott’s blog linked below. Visual Studio 2010 has two types of web projects; Web Application Project (WAP) and Website projects. You can use either project type with IIS Express.
Enabling IIS Express for web projects
For both WAP and Website projects which were using Cassini we have a very simply method for you to use IIS Express. You can just right click then select the context menu option “Use IIS Express”. Take a look at the screen shot that follows for that command.
After you do this your project will use IIS Express instead of Cassini going forward. If you wish to revert back to using Cassini you can just right click on the project and select “Use Visual Studio Development Server…” You can also make IIS Express your default web server for new projects as well.
For Web site projects when you create a new site you can create it such that IIS Express hosts it instead of Cassini. From Visual Studio when you select File->New-> Web Site you will see the New Web Site dialog. On that dialog you can click on the Browse button (see image below).
After you click that you will be prompted to enter the location where the site will be located. From there you can select “Local IIS” and the create a new IIS Express site for it.
In this dialog you need to select IIS Express Sites then click on the Create New Site button located towards the upper right hand corner. Once you do this it will create a new IIS Express site for your Web site.
Making IIS Express you default web server
In order to make IIS Express for new file based web projects you can go to the menu option Tools->Options->Projects and Solutions->Web Projects and check the “Use IIS Express for new file-based web sites and projects” check box. You can see this option in the next image.
After you have done this new projects/sites will use IIS Express by default. Note: if you have any existing projects/sites you will still have to “opt-in” to using IIS Express for each project.
Using IIS Express
After you have enabled IIS Express to be your projects web server, when you start debugging, or just start running your app, from Visual Studio you will see a new system tray icon appear (). You can right click on this icon to to quickly see what applications it is hosting. Each hosted application will have its own context menu. From this menu you can browse out to the application as well as stop it quickly.
You can also click on “Show All Applications” to open a dialog which give you more information about the sites that IIS Express is hosting. For example I opened this dialog and selected a running application and the result is shown in the image below.
There are a few notable values here
The URL for each hosted application
The Runtime version for the application
The path to the application
The path to the applicationHost.config file
The default location for the applicationHost.config file is your users’ directory. This enables IIS Express to run without requiring admin privileges. As you may know IIS (i.e. the full IIS) uses the applicationHost.config file to store its configuration. IIS Express is similar to IIS in that it uses a file also named applicationHost.config (not the same file as IIS though). The file that IIS uses is stored under the System32 directory and is shared across all users. The IIS Express config is specific to the current user. Regarding the runtime version, this is the version of the CLR which your application pool will use. For IIS Express application pools will, by default, use CLR 4.0. You can change this default in the applicationHost.config file for IIS Express. Visual Studio will assign the correct CLR version to your app pool based on the target framework version.
You can customize a few options for your site directly from Visual Studio. If you select your web project/site in the Solution Explorer and then open the Properties pane (you can right-click and select Properties on the project/site if it is not visible) you should see something similar to the following.
These settings will change how IIS Express hosts your site. One of the missing features of Cassini was the ability to host SSL sites. In IIS Express you can enable this. For example for this site I changed the value for SSL Enabled to be True, then a new URL was assigned so that I can use SSL to browse to the site. Please note that IIS Express will install a self-signed cert and you will see the following security warning from Internet Explorer when you browse to an https URL hosted by IIS Express.
One thing to make a note of is that when you change the settings for IIS Express here these settings are stored in the applicationHost.config file for IIS Express and not with the project/site itself. So if you are working in a team then your other team members will have to make the same changes. If you want to edit a setting which is not shown on the properties grid then you can edit the applicationHost.config file directly. You can easily open this file by clicking on the applicationHost.config link in the IIS Express dialog shown previously. For WAP projects you can change the port that is used from the Web tab in the project properties page.
Known issues
There are currently some known issues with IIS Express which are listed below. If you run into any more please let us know.
Edit and continue is not supported
Profiling is not supported
If you add a Web Deployment Project (WDP) to an IIS Express web site you will have to remove the ‘:’ from the name of the WDP
Some issues using WDP for IIS Express sites with sub-webs
One of the really cool features that we shipped for Visual Studio 2010 was web.config (XDT) transformations. Because the transformations are so simple and straightforward one of the first questions that someone asks after using it is “how can I use this in my other projects?” Unfortunately this feature is only built into the Web Application Projects (WAP). But it is very easy to reuse this because we just rely on an MSBuild task to do the heavy lifting for us. I received an email from that basically went like this
“Hi, I would like to use XDT transformations on my WPF project for both the app.config file as well as my unity.xml file. How can I do this?”
So one answer is to modify your project file to use the TransformXml task as I have blogged previously about (link below). But I thought that since this was such a common problem that I should go ahead and create a .targets file which would solve the above problem and could be re-used by anyone.
Let me clarify the scenario a bit before we dive into the details of the solution. I have create a sample Wpf project, named Wpf01. Inside of that project I have created these files:
app.confog
app.debug.config
app.release.config
Sample01.xml
Sample01.debug.xml
Sample01.release.xml
Sub\Sub\Sub01.xml
Sub\Sub\Sub01.debug.xml
Sub\Sub\Sub01.release.xml
Take a look at the image below (note: I manually edited the project file to make the file nest under each other, I will explain that shortly)
The files with .debug/.release are transform files. When I build I expect the following to happen:
Transform app.config with app.{Configuration}.config and write file to output folder with the correct name i.e. Wpf01.exe.config instead of just app.config
Transform Sample01.xml with Sample01.{Configuration}.config and write it to output folder with the name Sample01.config
Transform Sub\Sub\Sub01.xml with Sub\Sub\Sub01.{Configuration}.config and write it to the output folder with the name Sub\Sub\Sub01.xml
None of my source files should change
Usage
Before I get into the solution let me explain how to use the solution first because if you are not interested in the MSBuild details you can skip over that
You must have installed Web projects with Visual Studio on the machine (it contains the TransformXmll task).
Create the folder %ProgramFiles (x86)%\MSBuild\Custom. If you want to share this across team members then see my note at the end of this blog.
Download TransformFiles.targets (link below) and place the file into the folder %ProgramFiles (x86)%\MSBuild\Custom.
Edit your project file (right click on the project Unload Project, right click again and pick edit)
At the end of the project file place the element <Import Project="$(MSBuildExtensionsPath)\Custom\TransformFiles.targets" /> immediately above the closing </Project> tag
For files that you want transformed a metadata value of TransformOnBuild to true. See below on what this means.
Build and take a look at files in your output directory
For #5 lets examine the sample that I created. In this sample I had an app.config file. When I first created the project the entry in the project file for app.config looked like the following.
<None Include="app.config" />
So what you need to do is to add a new metadata value as described above for that. So it will turn into the following.
The transform targets will look for items that have this value declared on them and then during build it will transform them, if the transform file exists in the same folder as the file itself. You will need to add TransfromOnBuild to all the files that you want to transform. So in my case I added it to app.config, Sample01.xml and Sub01.xml. Note you should not add this to the transform files themselves because you will just waste your own time. After you do this you should perform a build then take a look at the output directory for your transformed files. The app.config should write out the the correct file and the others as expected.
Nest transforms under the source file
You might have noticed that in the image above that the transform files are nested under the files themselves. To do this you need to add the DependentUpon metadata value to the child items. For instance for app.config the child items look like the following.
If you are wondering how this works then this is the section for you. TransformFile.targets has 2 targets; DiscoverFilesToTransform and TransformAllFiles. DiscoverFilesToTransform looks through a set of items (None, Content, and Resource). Inside of DiscoverFilesToTransform I look for values with the %(TransformOnBuild)==true. After all of those are collected I identify if there is an app.config file being transformed and if so it is placed into a specific item list and all others go into another item list.
Inside of TransformAllFiles the TransformXml task is used to transform all of the files. This target injects itself into the build process by having the attribute AfterTargets="Build;_CopyAppConfigFile". So whenever the Build or _CopyAppConfigFile targets are called the TransformAllFiles target will execute.
Here if the full code for this file.
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<UsingTask TaskName="TransformXml"
AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll"/>
<ItemDefinitionGroup>
<!-- Set the default value to false here -->
<None>
<TransformOnBuild>false</TransformOnBuild>
</None>
<Content>
<TransformOnBuild>false</TransformOnBuild>
</Content>
<Resource>
<TransformOnBuild>false</TransformOnBuild>
</Resource>
<EmbeddedResource>
<TransformOnBuild>false</TransformOnBuild>
</EmbeddedResource>
<_FilesToTransform>
<IsAppConfig>false</IsAppConfig>
</_FilesToTransform>
</ItemDefinitionGroup>
<PropertyGroup>
<TransformAllFilesDependsOn>
DiscoverFilesToTransform;
</TransformAllFilesDependsOn>
</PropertyGroup>
<Target Name="TransformAllFiles" DependsOnTargets="$(TransformAllFilesDependsOn)" AfterTargets="Build;_CopyAppConfigFile">
<!-- Now we have the item list _FilesToTransformNotAppConfig and _AppConfigToTransform item lists -->
<!-- Transform the app.config file -->
<ItemGroup>
<_AppConfigTarget Include="@(AppConfigWithTargetPath->'$(OutDir)%(TargetPath)')" />
</ItemGroup>
<PropertyGroup>
<_AppConfigDest>@(_AppConfigTarget->'%(FullPath)')</_AppConfigDest>
</PropertyGroup>
<MakeDir Directories="@(_FilesToTransformNotAppConfig->'$(OutDir)%(RelativeDir)')"
Condition="Exists('%(RelativeDir)%(Filename).$(Configuration)%(Extension)')"/>
<TransformXml Source="@(_AppConfigToTransform->'%(FullPath)')"
Transform="%(RelativeDir)%(Filename).$(Configuration)%(Extension)"
Destination="$(_AppConfigDest)"
Condition=" Exists('%(RelativeDir)%(Filename).$(Configuration)%(Extension)') " />
<TransformXml Source="@(_FilesToTransformNotAppConfig->'%(FullPath)')"
Transform="%(RelativeDir)%(Filename).$(Configuration)%(Extension)"
Destination="@(_FilesToTransformNotAppConfig->'$(OutDir)%(RelativeDir)%(Filename)%(Extension)')"
Condition=" Exists('%(RelativeDir)%(Filename).$(Configuration)%(Extension)') " />
</Target>
<Target Name="DiscoverFilesToTransform">
<!--
This will look through items list: None & Content for those
with Metadata <TransformOnBuild>True</TransformOnBuild>
-->
<ItemGroup>
<_FilesToTransform Include="@(None);@(Content);@(Resource);@(EmbeddedResource)"
Condition=" '%(TransformOnBuild)' == 'true' "/>
</ItemGroup>
<PropertyGroup>
<_AppConfigFullPath>@(AppConfigWithTargetPath->'%(RootDir)%(Directory)%(Filename)%(Extension)')</_AppConfigFullPath>
</PropertyGroup>
<!-- Now look to see if any of these are the app.config file -->
<ItemGroup>
<_FilesToTransform Condition=" '%(FullPath)'=='$(_AppConfigFullPath)' ">
<IsAppConfig>true</IsAppConfig>
</_FilesToTransform>
</ItemGroup>
<ItemGroup>
<_FilesToTransformNotAppConfig Include="@(_FilesToTransform)"
Condition=" '%(IsAppConfig)'!='true'"/>
<_AppConfigToTransform Include="@(_FilesToTransform)"
Condition=" '%(IsAppConfig)'=='true'"/>
</ItemGroup>
</Target>
</Project>
Gaps
With most things found on blogs there are some gaps Those are described here.
Clean build => It’s a best practice to delete files upon clean, but in this case I am not. This would be pretty easy to add, if you are interested let us know and I will update the sample.
Incremental build => The transforms will run every time you build even if the outputs are up to date, if this is an issue for you let us know and I will update the sample.
Sharing with team members
If you want to share with team members instead of placing this into %ProgramFiles (x86)% just place it into a folder in version control then change the <Import statement to point to that file instead of using MSBuildExtensionPath.
If you end up using this please let us know what is your experience with it.
With Visual Studio 2010 when you package your application using the Build Deployment Package context menu option, see image below.
When build the package by default the package will be created in obj\{Configuration}\Package\{ProjectName}.zip where {Configuration} is the current build configuration, and {ProjectName} is the name of the project. So in this case I since I’m building with Debug and the project name is MvcApplication1 the package will be placed at obj\Debug\Package\MvcApplication1.zip. If you take this package and then import into IIS 7 with the “Import Application” option shown below. Note: The machine must have the Web Deployment Tool (aka MSDeploy) installed.
Once you click on Import Application then browse out to the package you will be shown a screen which prompts your for parameters. Its shown below.
On this screen you can see that we are prompting for a couple parameter values here. One is an IIS setting, Application Path, and the other is a connection string which will be placed inside the web.config file. If your Web Application Project (WAP) had 5 different connection strings then they would automatically show up here on this page. Since connection strings are replaced so often we create parameters for all connection strings by default. You can define new parameters on your own, quite easily actually, but that is the topic for another blog post.
Now back to the question. He is asking why do we “tokenize” the connection strings in web.config. To clarify take a look at my web.config file below.
After I perform a package this will get changed. Take a look @ the web.config file which resides in the package (you can get to the file at obj\{CofigurationName}\Package\PackageTmp\web.config). You will see what is shown below.
So his question is why is the connection string replaced with $(ReplacableToken_ApplicationServices-Web.config Connection String_0) and nothing else is? We do this because we do not want you to accidently copy your web to a location and have it executing SQL statements against a SQL server which you did not intend. The idea is that you will create a package that you can deploy to many different environments. So the value that was in your web.config (or web.debug.config/web.release.config if you are using a web.config transformation) will not be placed inside the web.config in the package. Instead those values will be used as defaults in the package itself. We also create a SetParameters.xml file for you so that you can tweak the values. For my app see the MvcApplication1.SetParameters.xml file below.
The idea is that you can deploy your package in 2 ways. Through the IIS Manager which will prompt you for the parameters or you can deploy using msdeploy.exe with the –setParamFile switch to specify the path to the SetParameters.xml file. In this case I could create a QA01.SetParameters.xml file along with a QA02.SetParameters.xml file to deploy my web to my two QA servers. How do we do this?
How connection strings are tokenized
You might be wondering how the connection strings are tokenized to begin with. With Visual Studio 2010 we released web.config transformations, which all you to write terse web.config transformations inside of files like web.debug.config/web.release.config. When you package/publish your web these transform files are used to transform your web.config based on what you expressed in the appropriate transform file. We have an MSBuild task TransformXml which performs the transformation. We use that same task to tokenize the connection strings. If you are interested in the details take a look at %ProgramFiles32%\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets in the AutoParameterizationWebConfigConnectionStringsCore target.
Now what if you do not want the connection string tokenized?
Prevent tokenizing connection strings
If you want to prevent your web.config connection strings from being tokenized it’s pretty easy. All we need to do is the add a property to the build/package/publish process. We can do that in 2 ways. Edit the project file itself or create a file with the name {ProjectName}.wpp.targets where {ProjectName} is the name of your project. The second approach is easier so I use that. In my case it would be MvcApplication1.wpp.targets. The contents of the file are shown below.
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<AutoParameterizationWebConfigConnectionStrings>false</AutoParameterizationWebConfigConnectionStrings>
</PropertyGroup>
</Project>
Note: You may need to reload the project in Visual Studio for this to take effect.
Inside of this file I have declared the property, AutoParameterizationWebConfigConnectionStrings, to be false. This is telling the Web Publishing Pipeline (WPP) that it should not replace replace the connection strings with tokens, instead leave them as they are.