- | rssFeed | My book on MSBuild and Team Build | Archives and Categories Thursday, May 09, 2013

Book published and now in stock!

I’m happy to say that my Supplement to Inside the Microsoft Build Engine book (co-author William Bartholomew) has now been published. In fact it’s already in stock and ready to be shipped by Amazon.com.

This book is a small addition (118 pages) to the previous book, Inside the Microsoft Build Engine 2nd edition. It has a small price too, MSRP is $12.99 but it’s selling on Amazon.com for $8.99! In this book we cover the updates to MSBuild, Team Build and Web Publishing in Visual Studio 2012. The foreword was written by Scott Hanselman, and you can read the entire foreword online.

Check out how thin the supplement is in comparison to the 2nd edition #ThinIsIn.

945231_10103483509401051_968543011_n

 

If you already own the 2nd edition then you’ll love this update.

 

Table of Contents

Chapter 1: What's new in MSBuild

  1. Visual Studio project compatibility between 2010 and 2012
  2. Out of Process Tasks
  3. NuGet
  4. XML Updates with SlowCheetah
  5. Cookbook
Chapter 2: What's new in Team Build 2012
  1. Installation
  2. Team Foundation Service
  3. User interface (UI) enhancements
  4. Visual Studio Test Runner
  5. Pausing build definitions
  6. Batching
  7. Logging
  8. Windows Workflow Foundation 4.5
  9. Cookbook
Chapter 3: What's new in Web Publishing
  1. Overview of the new Publish Web Dialog
  2. Building web packages
  3. Publish profiles
  4. Database publishing support
  5. Profile-specific web.config transforms
  6. Cookbook

 

The book has been available in e-book form for a few weeks. Just long enough for us to get our first review. It was 5 stars :).

image

 

Please let us know what you think of this book!

 

You can download all the samples and learn more at msbuildbook.com.

 

Sayed Ibrahim Hashimi | http://msbuildbook.com | @SayedIHashimi

msbuild | MSDeploy | Team Build | web | Web Publishing Pipeline Thursday, May 09, 2013 6:33:20 AM (GMT Daylight Time, UTC+01:00)  #     | 
Wednesday, March 06, 2013

How to publish one web project from a solution

Today on twitter @nunofcosta asked me roughly the question “How do I publish one web project from a solution that contains many?

The issue that he is running into is that he is building from the command line and passing the following properties to msbuild.exe.

    /p:DeployOnBuild=true
    /p:PublishProfile='siteone - Web Deploy'
    /p:Password=%password%

You can read more about how to automate publishing at http://sedodream.com/2013/01/06/CommandLineWebProjectPublishing.aspx.

When you pass these properties to msbuild.exe they are known as global properties. These properties are difficult to override and are passed to every project that is built. Because of this if you have a solution with multiple web projects, when each web project is built it is passed in the same set of properties. Because of this when each project is built the publish process for that project will start and it will expect to find a file named siteone – Web Deploy.pubxml in the folder Properties\PublishProfiles\. If the file doesn’t exist the operation may fail.

Note: If you are interested in using this technique for an orchestrated publish see my comments at http://stackoverflow.com/a/14231729/105999 before doing so.

So how can we resolve this?

Let’s take a look at a sample (see links below). I have a solution, PublishOnlyOne, with the following projects.

  1. ProjA
  2. ProjB

ProjA has a publish profile named ‘siteone – Web Deploy’, ProjB does not. When trying to publish this you may try the following command line.

    msbuild.exe PublishOnlyOne.sln /p:DeployOnBuild=true /p:PublishProfile=’siteone – Web Deploy’ /p:Password=%password%

See publish-sln.cmd in the samples.

If you do this, when its time for ProjB to build it will fail because there’s no siteone – Web Deploy profile for that project. Because of this, we cannot pass DeployOnBuild. Instead here is what we need to do.

  1. Edit ProjA.csproj to define another property which will conditionally set DeployOnBuild
  2. From the command line pass in that property

 

I edited ProjA and added the following property group before the Import statements in the .csproj file.

<PropertyGroup>
  <DeployOnBuild Condition=" '$(DeployProjA)'!='' ">$(DeployProjA)</DeployOnBuild>
</PropertyGroup>

 

Here you can see that DeployOnBuild is set to whatever value DeployProjA is as long as it’s not empty. Now the revised command is:

    msbuild.exe PublishOnlyOne.sln /p:DeployProjA=true /p:PublishProfile=’siteone – Web Deploy’ /p:Password=%password%

Here instead of passing DeployOnBuild, I pass in DeployProjA which will then set DeployOnBuild. Since DeployOnBuild wasn’t passed to ProjB it will not attempt to publish.

 

You can find the complete sample at https://github.com/sayedihashimi/sayed-samples/tree/master/PublishOnlyOne.

 

Sayed Ibrahim Hashimi | @SayedIHashimi | http://msbuildbook.com/

MSDeploy | web | Web Deployment Tool | Web Development | Web Publishing Pipeline Wednesday, March 06, 2013 2:48:41 AM (GMT Standard Time, UTC+00:00)  #     | 
Sunday, January 06, 2013

Command line web project publishing

With the release of VS2012 we have improved the command line publish experience. We’ve also made all the web publish related features available for VS2010 users in the Azure SDK.

The easies way to publish a project from the command line is to create a publish profile in VS and then use that. To create a publish profile in Visual Studio right click on the web project and select Publish. After that it will walk you though creating a publish profile. VS Web publish profile support the following publish methods.

Command line publishing is only supported for Web Deploy, Web Deploy Package, and File System. If you think we should support command line scenarios for other publish methods the best thing to do would be to create a suggestion at http://aspnet.uservoice.com. If there is enough interest we may work on that support.

Let’s first take a look at how you can publish a simple Web project from the command line. I have created a simple Web Forms project and want to publish that. I’ve created a profile named SayedProfile. In order to publish this project I will execute the following command.

msbuild MyProject.csproj /p:DeployOnBuild=true /p:PublishProfile=<profile-name> /p:Password=<insert-password> /p:VisualStudioVersion=11.0

In this command you can see that I have passed in these properties;

You may not have expected the VisualStudioVersion property here. This is a new property which was introduced with VS 2012. It is related to how VS 2010 and VS 2012 are able to share the same projects. Take a look at my previous blog post at http://sedodream.com/2012/08/19/VisualStudioProjectCompatabilityAndVisualStudioVersion.aspx. If you are building the project file, instead of the solution file then you should always set this property.

If you are publishing using the .sln file you can omit the VisualStudioVersion property. That property will be derived from the version of the solution file itself. Note that there is one big difference when publishing using the project or solution file. When you build an individual project the properties you pass in are given to that project alone. When you build from the command line using the solution file, the properties you have specified are passed to all the projects. So if you have multiple web projects in the same solution it would attempt to publish each of the web projects.

FYI in case you haven’t already heard I’m working on an update to my book. More info at msbuildbook.com

Sayed Ibrahim Hashimi | @SayedIHashimi

msbuild | MSBuild 4.0 | MSDeploy | web | Web Deployment Tool Sunday, January 06, 2013 2:56:37 AM (GMT Standard Time, UTC+00:00)  #     | 
Wednesday, December 19, 2012

How to sync multiple folders with Web Deploy (MSDeploy)

I received a customer email and one of the things that he wants to be able to do is sync multiple folders. I thought I’d share with you what I wrote to him.

From: Sayed Hashimi
Sent: Tuesday, December 18, 2012 11:28 PM

You actually can do this, but it’s not based on skips, it’s an opt-in approach. What I mean is that you would have to specify all the folders that you wanted to sync.

MSDeploy is a provider based model. There is an composite provider, manifest, which can be used when multiple providers are required. In your case the actual provider that you want to use is contentPath. This is the provider that knows how to sync folders. If you want to sync multiple folders you can create a source manifest which has the source folders and a dest manifest which has all the target folders.

In my example I have the following folders.

I only want to sync 01 and 03 so I create the manifest with the following content.

<?xml version="1.0" encoding="utf-8"?>
<sitemanifest>
  <contentPath path="C:\Temp\publish\Source\01"/>
  <contentPath path="C:\Temp\publish\Source\03"/>
</sitemanifest>

The dest manifest file will contain.

<?xml version="1.0" encoding="utf-8"?>
<sitemanifest>
  <contentPath path="C:\Temp\publish\Dest\01"/>
  <contentPath path="C:\Temp\publish\Dest\03"/>
</sitemanifest>

Then to do the sync you can use the command.

msdeploy -verb:sync -source:manifest="C:\Temp\publish\SourceManifest.xml" -dest:manifest="C:\Temp\publish\DestManifest.xml" -enableRule:DoNotDelete -useCheckSum -disableRule:BackupRule

You can see that I use the manifest provider for both the source and the dest. A few things to note.

Drawbacks from this approach

How you can make this even better

The real issue I have with this approach is that it requires both a source & dest manifest. If you can easily auto generate these files from a list of shares that would be great. If you are maintaining these files “by hand” you should be careful to make sure both files are updated.

With a bit of more work you can boil it down to a single source manifest if you have a common root folder, and you want the files to be reflected in the same relative structure underneath that. They way that you would do this is to use the MSDeploy auto provider trick. With MSDeploy you can pass –dest:auto and MSDeploy will essentially reflect the source settings to the destination. You can then create an MSDeploy parameter which will be used to update the path of that common root folder.

If you want to go down this option it will be a bit more complex. I’d be willing to walk you through it if you’d be willing to blog about it afterwards J

Thanks,
Sayed Ibrahim Hashimi | @SayedIHashimi

MSDeploy Wednesday, December 19, 2012 7:34:19 AM (GMT Standard Time, UTC+00:00)  #     | 
Saturday, October 27, 2012

MSBuild: how to set the configuration property

When you are building a .sln file or a .csproj/.vbproj/etc you need to be careful how you set the Configuration property. Once this property is set you do not want to change the value of it. Because of this it is best to specify this as a global property. To do that you can pass it in on the command line. If you are using the MSBuild task then you can pass it in via Properties or AdditionalProperties. What you do not want to do is to set this value inside your .csproj/.vbproj or any imported file. The only time when this is OK if there is a condition which will not set the property if it’s already been set. This is exactly how the default .csproj/.vbproj files are authored:

<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

If you do set this property w/o the conditional not to overwrite an existing value you may experience really strange behavior during your builds. And it may be difficult to diagnose the issue as well.

Now let me explain why you cannot do this. When you build a .csproj/.vbproj MSBuild will start creating an in-memory representation of the entire project. It will start with the .csproj/.vbproj file itself. It will read the file from top to bottom. When a property is encountered it is evaluated. If a property is encountered that relies on another one, for example

<IntermediateOutputPath Condition=" '$(PlatformName)' == 'AnyCPU' ">$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>

The properties inside the expression will be evaluated on whatever values exist for the properties at the time. In this case ItermediateOutputPath will be the value of BaseIntermediateOutputPath and Configuration.

If a property is encountered which specifies a value for a property which has been previously declared, the previous value will be discarded.

The implications of this are subtle but very simple; once a property has been set which has dependent properties you must not overwrite that property. This is because when a dependent property is encountered it is evaluated immediately. You cannot re-evaluate that property. So if you set a property during your build, some existing dependent properties which were evaluated before the value change will continue to use the old value. There is no way to re-evaluate those properties.

Now lets see how this relates to the Configuration property specifically.

The contents of the .csproj/.vbproj are properties/items along with an import to Microsoft.csharp.targets (Microsoft.VisualBasic.targets for .vbproj) which then imports Microsoft.Common.targets. If you look in Microsoft.common.targets you will see many different properties which are declared using $(Configuration). So this means that you must treat the Configuration property with care and abide by the rule that I have outlined above.

FYI If you want more details on this I have explained this entire process in great detail in my book Inside MSBuild and Team Build.

Configuration for web publishing

If you have used the new web publish experience in Visual Studio 2012 (also available for VS2010 from the Azure SDK) you may have noticed that the web publish profiles are MSBuild files. They are stored under Properties\PublishProfiles (My Project\PublishProfiles for VB) and have extensions of .pubxml. In that file (or in a .pubxml.user file associated with it) you will find a property defined as

<LastUsedBuildConfiguration>Release</LastUsedBulidConfiguration>

This value corresponds to the value for the Configuration drop down in the VS web publish dialog. When you kick off a publish in VS we use this value and kick off a build and specify Configuration as a global property which is passed in. The reason why we did not name this property Configuration is because the web publish profile is imported into the web project itself during the publish process. By the file being imported you can natively access all the properties/items of the .csproj/.vbproj and also easily extend the build process. Since that is the case we cannot set the Configuration property because we know it’s value has already been set. Due to this when publishing from the command line you must specify the Configuration property.

Sayed Ibrahim Hashimi | @SayedIHashimi

msbuild | MSDeploy | Visual Studio | Visual Studio 2008 | Visual Studio 2010 Saturday, October 27, 2012 3:49:02 AM (GMT Daylight Time, UTC+01:00)  #     | 
Monday, August 20, 2012

Web Deploy (MSDeploy) how to sync a folder

Today I saw the following question on StackOverflow MSDeploy - Deploying Contents of a Folder to a Remote IIS Server and decided to write this post to answer the question.

Web Deploy (aka MSDeploy) uses a provider model and there are a good number of providers available out of the box. To give you an example of some of the providers; when syncing an IIS web application you will use iisApp, for an MSDeploy package you will use package, for a web server webServer, etc. If you want to sync a local folder to a remote IIS path then you can use the contentPath provider. You can also use this provider to sync a folder from one website to another website.

The general idea of what we want to do in this case is to sync a folder from your PC to your IIS website. Calls to msdeploy.exe can be a bit verbose so let’s construct the command one step at at time. We will use the template below.

msdeploy.exe -verb:sync -source:contentPath="" -dest:contentPath=""

We use the sync verb to describe what we are trying to do, and then use the contentPath provider for both the source and the dest. Now let’s fill in what those values should be. For the source value you will need to pass in the full path to the folder that you want to sync. In my case the files are at C:\temp\files-to-pub. For the dest value you will give the path to the folder as an IIS path. In my case the website that I’m syncing to is named sayedupdemo so the IIS path that I want to sync is ‘sayedupdemo/files-to-pub’. Now that give us.

msdeploy.exe –verb:sync -source:contentPath="C:\temp\files-to-pub" -dest:contentPath='sayedupdemo/files-to-pub'

For the dest value we have not given any parameters indicating what server those command are supposed to be sent to. We will need to add those parameters. The parameters which typically need to be passed in are.

In my case I’m publishing to a Windows Azure Web Site. So the values that I will use are:

All of these values can be found in the .publishSettings file (can be downloaded from Web Site dashboard from WindowsAzure.com). For the ComputerName value you will need to append the name of your site to get the full URL. In the example above I manually added ?site=sayedupdemo, this is the same name as shown in the Azure portal. So now the command which we have is.

msdeploy.exe 
    –verb:sync 
    -source:contentPath="C:\temp\files-to-pub" 
    -dest:contentPath='sayedupdemo/files-to-pub'
            ,ComputerName="https://waws-prod-blu-001.publish.azurewebsites.windows.net/msdeploy.axd?site=sayedupdemo"
            ,UserName='$sayedupdemo'
            ,Password='thisIsNotMyRealPassword'
            ,AuthType='Basic' 

OK we are almost there! In my case I want to make sure that I do not delete any files from the server during this process. So I will also add –enableRule:DoNotDeleteRule. So our command is now.

msdeploy.exe 
    –verb:sync 
    -source:contentPath="C:\temp\files-to-pub" 
    -dest:contentPath='sayedupdemo/files-to-pub'
            ,ComputerName="https://waws-prod-blu-001.publish.azurewebsites.windows.net/msdeploy.axd?site=sayedupdemo"
            ,UserName='$sayedupdemo'
            ,Password='thisIsNotMyRealPassword'
            ,AuthType='Basic' 
    -enableRule:DoNotDeleteRule 

At this point before I execute this command I’ll first execute it passing –whatif. This will give me a summary of what operations will be without actually causing any changes. When I do this the result is shown in the image below.

SNAGHTML204f5cd

After I verified that the changes are all intentional, I removed the –whatif and executed the command. After that the local files were published to the remote server. Now that I have synced the files each publish after this will be result in only changed files being published.

If you want to learn how to snyc an individual file you can see my previous blog post How to take your web app offline during publishing.

dest:auto

In the case of the question it was asked with dest:auto, you can use that but you will have to pass in the IIS app name as a parameter and it will replace the path to the folder. Below is the command.

msdeploy.exe 
    -verb:sync
    -source:contentPath="C:\temp\files-to-pub" 
    -dest:auto
        ,ComputerName="https://waws-prod-blu-001.publish.azurewebsites.windows.net/msdeploy.axd?site=sayedupdemo"
        ,UserName='$sayedupdemo'
        ,Password='thisIsNotMyRealPassword'
        ,AuthType='Basic' 
-enableRule:DoNotDeleteRule 
-setParam:value='sayedupdemo',kind=ProviderPath,scope=contentPath,match='^C:\\temp\\files-to-pub$'

Thanks,
Sayed Ibrahim Hashimi @SayedIHashimi

MSDeploy | Visual Studio | web | Web Deployment Tool Monday, August 20, 2012 4:08:11 AM (GMT Daylight Time, UTC+01:00)  #     | 
Monday, August 06, 2012

Plans regarding Website projects and Web Deployment Projects

The release of Visual Studio 2012 is right around the corner. If you’ve been following our blog/twitter then you may know that many of the Web related components of Visual Studio are now“out-of-band”, meaning that we can update them independently of Visual Studio itself. Because of this we are planning to ship updates a few times a year. We are currently in the process for planning our first update for VS 2012 and we wanted to share some of the items that we are planning to work on. We would like to get your feedback on these ideas to ensure that we are doing the right things. If you have comments please do let us know. FYI the updates that I describe below will be made available for both VS 2012 as well as VS 2010.

Website Project Updates

When you use Visual Studio there are two types of web projects you can create: a Web Application Project (WAP, this includes MVC) and a Website Project (WSP). In VS 2012 we did a lot of work to update the publish experience for WAPs. When we set out for these updates we planned to take these enhancements and make the available to Website projects as well. As we progressed it became evident that we did not have the resources to implement the features for both WAP and WSP in time for VS 2012. So we focused on creating the right experience for WAPs and we also added an extensibility point into WSP which will allow us to replace the existing publish dialog. The reason why we focused on WAP first was because WAPs already have support for Web Deploy (MSDeploy) based publishing as well as a formal build/publish process captured in MSBuild. WSP does not have either of these so it would have taken more time to start with WSP.

When VS 2012 is released the publish experience for WSP will be the same which was available in VS2010 but we will have a release a few months after the release which will bring all the publish goodness to Website Projects! This will include all the features which are available to Web Application Projects including; the ability to publish using.

Since both project systems will be using the exact same code whenever we add a feature it will immediately be available to both. In today’s world they are two entirely different code bases (the WSP publishing experience is currently native code where as the WAP publish dialog is managed). This will allow us to maintain a consistent publish experience and also enable us to deliver features more quickly.

Since WSP does not have a “build” process you might be wondering how we are planning to hook this all together since our entire publish pipeline is captured in MSBuild. Here is a rough idea of what we are currently thinking. After you use the new publish dialog to create a publish profile for the first time we will do a number of things:

  1. Create a new folder to contain needed artifacts
    1. The folder may be in the root of the Website project, but we are considering placing it somewhere outside as well
    2. The name of this folder is not yet finalized, but it could be something like _Publish or _Project
  2. Create an MSBuild file for the Website in that folder, this will capture information like; included files, references, properties to control publish process
    1. The primary purpose of dropping this file is to facilitate command line publish scenarios, without this we could publish from Visual Studio but not from the command line
    2. When you make changes in Visual Studio like adding a reference we will automatically keep this file up to date
  3. Create the publish profile in that folder (this is a .pubxml file)
  4. When the site is being published the working directory (i.e. obj\ folder) will be outside the root of the website, most likely in the same folder which contains the WSP root

After we have those things in place for the most part the publish dialog will be able to treat both projects in the same way. These files will by default be stored in version control and can be shared with other team members. Sensitive information such as the MSDeploy password will be stored in another file and encrypted per-user/per-machine in a .user file which is not checked in.

Web Deployment Projects

A few months after Visual Studio 2005 shipped we released the first version of Web Deployment Projects, and we updated WDP for both VS 2008 and VS 2010 and released them a few months after each of those releases as well. WDPs are used for a few different scenarios including the following.

  1. Publishing a Website project using MSDeploy
  2. Command line publish support
  3. Customizing the publish process for a WAP
  4. Running ASP.NET precompile/merge for a WSP or WAP

When we looked at the scenarios that WDPs are typically used for and then compared that to features which we have for WAP and WSP (after the updates mentioned above) we noticed that most (if not all) scenarios where WDP is used can be covered without requiring a WDP. Our new publish experience already has first class support for MSDeploy, command line publishing, and for extensibility so that covers #1-#3. Regarding #4 for WAPs we have already added ASP.NET precompile/merge as a publish option (you can find it in the Package/Publish Web tab). Since WSP does not have any property pages we are likely to move that option to being on the publish dialog itself or we will expose those options in another way for WSP. We have not yet settled on that design.

It may not seem like it but updating WDP to support VS2012 is a significant effort. Knowing that, and that most of the scenarios where WDP are used can now be transitioned to the new experience, we have decided to invest in giving WSP projects first class publishing support instead of updating VS 2012 to support WDP. We think that this is the right decision because we are unifying the publish experience for both project systems and it allows us to create a deeper set of features going forward instead of investing in different things and wasting effort. If you have a scenario that you think we have missed please do not hesitate to reach out to me by email at sayedha@microsoft.com and let me know.


Sayed Ibrahim Hashimi | @SayedIHashimi

asp.net | MSDeploy | Visual Studio | Visual Studio 2010 | Visual Studio 2012 | Web Publishing Pipeline Monday, August 06, 2012 10:16:47 PM (GMT Daylight Time, UTC+01:00)  #     | 
Friday, June 15, 2012

Visual Studio 2010 Web Publish Updates

Last week we rolled out some updates for our Visual Studio 2010 Web Publishing Experience. This post will give you an overview of the new features which we released. In the coming weeks there will be more posts getting into more details regarding individual features.

You can get these updates in the Windows Azure SDK for Visual Studio 2010. When you download that package there you will also get the latest tools for Azure development.

The new high level features include the following.

Overview

When you right click on your Web Application Project (WAP) you will now see the new publish dialog.

image

On this tab you can import a .publishSettngs file, which many web hosts provide, and you can also manage your publish profiles. If you are hosting your site on Windows Azure Web Sites then you can download the publish profile on the dashboard of the site using the Download publish profile link. After you import this publish profile you will be brought to the Connection tab automatically.

image

On this tab you can see all the server configuration values which are needed for your client machine to connect to the server. Typically you don’t have to worry about the details of these values. Next you’ll go to the Settings tab.

image

On the Settings tab you can set the build configuration which should be used for the publish process, the default value here is Release. There is also a checkbox to enable you to delete any files on the server which do not exist in the project.

Below that checkbox you will see a section for databases. The sample project shown has an Entity Framework Code First model, named ContactsContext, and it uses Code First Migrations to manage the database schema. If you have any non-EF Code First connection strings in web.config then those databases will show up as well but the support for incrementally publishing the schema for those has not yet been finalized. We are currently working on that. You can visit my previous blog entry for more info on that.

If you imported a .publishSettings file with a connection string then that connection string would automatically be inserted in the textbox/dropdown for the connection string. If you did not then you can use the … button to create a connection string with the Connection String Builder dialog or you can simply type/paste in a connection string. For the EF Code First contexts you will see the Execute Code Frist Migrations checkbox. When you check this when your site is published the web.config will be transformed to enable the Code First migrations to be executed the first time that the context is accessed. Now you can move to the Preview tab.

When you first come to the Preview tab you will see a Start Preview button. Once you click this button you will see the file operations which would be performed once you publish. Since this site has never been published all the file operations are Add, as you can see in the image below. The other Action values include; Update and Delete.

image

Once you are ready to publish you can click the Publish button. You can monitor the progress of the publish process using the Output Window. If your publish profile had a value for the Destination URL then the site will automatically be opened in the default browser after the publish has successfully completed.

Publish Profiles

One of the other changes in the publish experience is that publish profiles are now stored as a part of your project. They are stored under the folder Properties\PublishProfiles (for VB projects its My Project\PublishProfiles) and the extension is .pubxml. You can see this in the image below.

image

These .pubxml files are MSBuild files and you can modify these files in order to customize the publish process. If you do not want the publish profile to be checked into version control you can simply exclude it from the project. The publish dialog will look at the files in the PublishProfiles folder so you will still be able to publish using that profile. You can also leverage these publish profiles to simply publishing from the command line. For example you can use the following syntax to publish from the command line.

msbuild.exe WebApplication2.csproj /p:DeployOnBuild=true;PublishProfile="pubdemo - Web Deploy";Password={INSERT-PASSWORD}

 

Resources

If you have any questions please feel free to directly reach out to me at sayedha(at){MicrosoftDOTCom}.

Sayed Ibrahim Hashimi @SayedIHashimi

asp.net | Microsoft | MSDeploy | Visual Studio 2010 | web | Web Deployment Tool | Web Publishing Pipeline Friday, June 15, 2012 8:07:30 PM (GMT Daylight Time, UTC+01:00)  #     | 
Sunday, May 13, 2012

VS Web Publish: How to parameterize connection strings outside of web.config

If you have used the Visual Studio web publish in either VS 2010 or VS 11 to create Web Deploy packages then you probably know that we parameterize connection strings in web.config automatically. In case you are not familiar with Web Deploy parameters, they are a way to declare that you want to easily be able to update a value of something when publishing the package later on. Connection strings are good examples of something which typically needs to be updated during publish.

As I previously stated if you create a Web Deploy package in Visual Studio we will automatically create Web Deploy parameters for all your connection strings in web.config. Earlier today I saw a question on StackOverflow asking how to parameterize connection strings in non-web.config files (question actually asked something else, but I think this is what he’s really wanting). I created a sample showing how to do this. Below is what the connectionStrings element looks like in web.config.

<connectionStrings configSource="connectionStrings.config" />

And here is connectionStrings.config

<?xml version="1.0" encoding="utf-8" ?>
<connectionStrings>
  <clear/>
  <add name="ApplicationServices"
           connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnetdb.mdf;User Instance=true"
           providerName="System.Data.SqlClient" />
  <add name="OtherConnectionString"
       connectionString="data source=.\SQLExpress;Integrated Security=SSPI;Initial Catalog=foo"
       providerName="System.Data.SqlClient"/>
</connectionStrings>

In order to parameterize these connection strings you will have to extend the Web Publish Pipeline. To do that create a file named {project-name}.wpp.targets in the root of the project in which you are working (for VS 11 projects you can place all this directly inside of the .pubxml files). This will be an MSBuild file which will get imported into the build/publish process. Below is the file which needs to be created.

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <ItemGroup>
    <!-- Here we need to declare MSDeploy parameters for connection strings in connectionStrings.config -->
    <MsDeployDeclareParameters Include="ApplicationServices-ConnectionString" >
      <Kind>XmlFile</Kind>
      <Scope>connectionStrings.config$</Scope>
      <Match>/connectionStrings/add[@name='ApplicationServices']/@connectionString</Match>
      <Description>Connection string for ApplicationServices</Description>
      <DefaultValue>data source=(localhost);Initial Catalog=AppServices</DefaultValue>
      <Tags>SqlConnectionString</Tags>
    </MsDeployDeclareParameters>

    <MsDeployDeclareParameters Include="OtherConnectionString-ConnectionString" >
      <Kind>XmlFile</Kind>
      <Scope>connectionStrings.config$</Scope>
      <Match>/connectionStrings/add[@name='OtherConnectionString']/@connectionString</Match>
      <Description>Connection string for OtherConnectionString</Description>
      <DefaultValue>data source=(localhost);Initial Catalog=OtherDb</DefaultValue>
      <Tags>SqlConnectionString</Tags>
    </MsDeployDeclareParameters>
  </ItemGroup>

</Project>

Here you can see that I am creating values for MSDeployDeclareParameters. When you package/publish this item list is used to create the MSDeploy parameters. Below is an explanation of the metadata values each contain.

After you create this file you will need to close/re-open VS (it caches imported .targets files). Then you can create a web deploy package. When you do so these new parameters will be declared. In my case I then imported this in the IIS manager and here is the dialog which shows up for the parameters.

SNAGHTML94cce08

As you can see the Application Path parameter is shown there as well as my custom connection string values. When I update the values in the text box and opened connectionStrings.config on my web server they were the values I entered in the dialog box.

FYI I have uploaded this sample to my github account at ParameterizeConStringConfig.

Sayed Ibrahim Hashimi @SayedIHashimi

msbuild | MSBuild 4.0 | MSDeploy | Visual Studio | Web Deployment Tool | Web Publishing Pipeline Sunday, May 13, 2012 10:18:03 PM (GMT Daylight Time, UTC+01:00)  #     | 
Wednesday, March 14, 2012

Package web updated and video below

A couple months ago I blogged about a Package-Web which is a NuGet package that extends the web packaging process in Visual Studio to enable you to create a single package which can be published to multiple environments (it captures all of your web.config transforms and has the ability to transform on non-dev machines). Since that release I have updated the project and tonight I created a video which shows the features a bit you can check it out on Youtube. It’s embedded below.

You can install this via NuGet, the package name is PackageWeb.

image

Package-Web is an open source project and you can find it on my github account at https://github.com/sayedihashimi/package-web.

Thanks,
Sayed Ibrahim Hashimi @SayedIHashimi

msbuild | MSDeploy | Visual Studio | web | Web Deployment Tool | Web Development | Web Publishing Pipeline Wednesday, March 14, 2012 6:08:57 AM (GMT Standard Time, UTC+00:00)  #     | 
Saturday, February 18, 2012

How to create a Web Deploy package when publishing a ClickOnce project

The other day I saw a question on StackOverflow (link in resources below) asking How you can create a Web Deploy (AKA MSDeploy) package when publishing a ClickOnce project. The easiest way to do this is to use the Web Deploy command line utility, msdeploy.exe. With the command line you can easily create an MSDeploy package from a folder with a command like the following:

    %msdeploy% 
      -verb:sync 
      -source:contentPath="C:\Temp\_NET\WebPackageWithClickOnce\WebPackageWithClickOnce\bin\Debug\app.publish" 
      -dest:package="C:\Temp\_NET\WebPackageWithClickOnce\WebPackageWithClickOnce\bin\Debug\co-pkg.zip"

 

Here you can see that I’m using the sync verb, along with a contentPath provider (which points to a folder) as the source and the destination is using the package provider, this point to where I want the package to be stored.

Now that we understand how to create an MSDeploy package from a folder we need to extend the ClickOnce publish process to create a package. I’m not a ClickOnce expert, but the ClickOnce publish process is captured in MSBuild so after investigating for a bit I found the following relevant details.

Now that we know what target to extend as well as what property we can use to refer to the folder which has the content we can complete sample. We need to edit the project file. Below is the full contents which I have placed at the bottom of the project file (right above </Project>).

  <PropertyGroup>
    <WebDeployPackageName Condition=" '$(WebDeployPackageName)'=='' ">$(MSBuildProjectName).zip</WebDeployPackageName>
    <!--Unless specified otherwise, the tools will go to HKLM\SOFTWARE\Microsoft\IIS Extensions\MSDeploy\1 to get the installpath for msdeploy.exe.-->
    <MSDeployPath Condition="'$(MSDeployPath)'==''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\IIS Extensions\MSDeploy\3@InstallPath)</MSDeployPath>
    <MSDeployPath Condition="'$(MSDeployPath)'==''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\IIS Extensions\MSDeploy\2@InstallPath)</MSDeployPath>
    <MSDeployPath Condition="'$(MSDeployPath)'==''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\IIS Extensions\MSDeploy\1@InstallPath)</MSDeployPath>
    <MSDeployExe Condition=" '$(MSDeployExe)'=='' ">$(MSDeployPath)msdeploy.exe</MSDeployExe>
  </PropertyGroup>
  <Target Name="CreateWebDeployPackage" AfterTargets="Publish" DependsOnTargets="Publish">
    <!--
    %msdeploy% 
      -verb:sync 
      -source:contentPath="C:\Temp\_NET\WebPackageWithClickOnce\WebPackageWithClickOnce\bin\Debug\app.publish" 
      -dest:package="C:\Temp\_NET\WebPackageWithClickOnce\WebPackageWithClickOnce\bin\Debug\co-pkg.zip"
      -->
    <PropertyGroup>
      <Cmd>"$(MSDeployExe)" -verb:sync -source:contentPath="$(MSBuildProjectDirectory)\$(PublishDir)" -dest:package="$(OutDir)$(WebDeployPackageName)"</Cmd>
    </PropertyGroup>
    <Message Text="Creating web deploy package with command: $(Cmd)" />
    <Exec Command="$(Cmd)" />
  </Target>

Here I’ve created a couple properties as well as a new target, CreateWebDeployPackage. I have declared the property WebDeployPackageName which will be the name (excluding path) of the Web Deploy package which gets created. This defaults to the name of the project, but you can override it if you want. Next I define the property, MSDeployPath, which points to msdeploy.exe. It will pick the latest version.

The CreateWebDeployPackage target just constructs the full command line call which needs to be executed and invokes it using the Exec MSBuild task. There are a couple subtle details on the target itself though which are worth pointing out. The target has declared AfterTargets=”Publish” which means that it will be invoked after the Publish target. It also declares DependsOnTargets=”Publish”. Which means that whenever the target gets invoked that Publish will need to be executed before CreateWebDeployPackage.

Now that we have defined these updates when you publish your ClickOnce project (wither through Visual Studio or the command line/build servers) a Web Deploy package will be generated in the output folder which you can use to incrementally publish your ClickOnce app to your web server. You can find the latest version of this sample on my github repository.

Sayed Ibrahim Hashimi @SayedIHashimi

Resources

ClickOnce | IIS | Microsoft | msbuild | MSDeploy | web Saturday, February 18, 2012 6:47:30 PM (GMT Standard Time, UTC+00:00)  #     | 
Tuesday, February 14, 2012

How to update a single file using Web Deploy (MSDeploy)

The other day I saw a question posted on StackOverflow (link to question below in resources section) asking if it was possible to update web.config using MSDeploy. I actually used a technique where I updated a single file in one of my previous posts at How to take your web app offline during publishing but it wasn’t called out too much. In any case I’ll show you how you can update a single file (in this case web.config) using MSDeploy.

You can use the contentPath provider to facilitate updating a single file. Using contentPath you can sync either a single file or an entire folder. You can also use IIS app paths to resolve where the file/folder resides. For example if I have a web.config file in a local folder named “C:\Data\Personal\My Repo\sayed-samples\UpdateWebConfig” and I want to update my IIS site UpdateWebCfg running in the Default Web Site on my folder I would use the command shown below.

%msdeploy% -verb:sync -source:contentPath="C:\Data\Personal\My Repo\sayed-samples\UpdateWebConfig\web.config" -dest:contentPath="Default Web Site/UpdateWebCfg/web.config"

From the command above you can see that I set the source content path to the local file and the dest content path using the IIS path {SiteName}/{AppName}/{file-path}. In this case I am updating a site running in IIS on my local machine. In order to update one that is running on a remote machine you will have to add ComputerName and possibly some other values to the –dest argument.

You can view the latest sources for this sample at my github repo, link is below.

 

Hope that helps!

Sayed Ibrahim Hashimi – @SayedIHashimi

Resources:

IIS | MSDeploy | web | Web Publishing Pipeline Tuesday, February 14, 2012 7:17:30 PM (GMT Standard Time, UTC+00:00)  #     | 
Sunday, January 08, 2012

How to take your web app offline during publishing

I received a customer email asking how they can take their web application/site offline for the entire duration that a publish is happening from Visual Studio. An easy way to take your site offline is to drop an app_offline.htm file in the sites root directory. For more info on that you can read ScottGu’s post, link in below in resources section. Unfortunately Web Deploy itself doesn’t support this Sad smile. If you want Web Deploy (aka MSDeploy) to natively support this feature please vote on it at http://aspnet.uservoice.com/forums/41199-general/suggestions/2499911-take-my-site-app-offline-during-publishing.

Since Web Deploy doesn’t support this it’s going to be a bit more difficult and it requires us to perform the following steps:

  1. Publish app_offline.htm
  2. Publish the app, and ensure that app_offline.htm is contained inside the payload being published
  3. Delete app_offline.htm

#1 will take the app offline before the publish process  begins.
#2 will ensure that when we publish that app_offline.htm is not deleted (and therefore keep the app offline)
#3 will delete the app_offline.htm and bring the site back online

Now that we know what needs to be done let’s look at the implementation. First for the easy part. Create a file in your Web Application Project (WAP) named app_offline-template.htm. This will be the file which will end up being the app_offline.htm file on your target server. If you leave it blank your users will get a generic message stating that the app is offline, but it would be better for you to place static HTML (no ASP.NET markup) inside of that file letting users know that the site will come back up and whatever other info you think is relevant to your users. When you add this file you should change the Build Action to None in the Properties grid. This will make sure that this file itself is not published/packaged. Since the file ends in .htm it will by default be published. See the image below.

image

Now for the hard part. For Web Application Projects we have a hook into the publish/package process which we refer to as “wpp.targets”. If you want to extend your publish/package process you can create a file named {ProjectName}.wpp.targets in the same folder as the project file itself. Here is the file which I created you can copy and paste the content into your wpp.targets file. I will explain the significant parts but wanted to post the entire file for your convince. Note: you can grab my latest version of this file from my github repo, the link is in the resource section below.

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="InitalizeAppOffline">
    <!-- 
    This property needs to be declared inside of target because this is imported before
    the MSDeployPath property is defined as well as others -->
    <PropertyGroup>
      <MSDeployExe Condition=" '$(MSDeployExe)'=='' ">$(MSDeployPath)msdeploy.exe</MSDeployExe>
    </PropertyGroup>    
  </Target>

  <PropertyGroup>
    <PublishAppOfflineToDest>
      InitalizeAppOffline;
    </PublishAppOfflineToDest>
  </PropertyGroup>

  <!--
    %msdeploy% 
      -verb:sync 
      -source:contentPath="C:\path\to\app_offline-template.htm" 
      -dest:contentPath="Default Web Site/AppOfflineDemo/app_offline.htm"
  -->

  <!--***********************************************************************
  Make sure app_offline-template.htm gets published as app_offline.htm
  ***************************************************************************-->
  <Target Name="PublishAppOfflineToDest" 
          BeforeTargets="MSDeployPublish" 
          DependsOnTargets="$(PublishAppOfflineToDest)">
    <ItemGroup>
      <_AoPubAppOfflineSourceProviderSetting Include="contentPath">
        <Path>$(MSBuildProjectDirectory)\app_offline-template.htm</Path>
        <EncryptPassword>$(DeployEncryptKey)</EncryptPassword>
        <WebServerAppHostConfigDirectory>$(_MSDeploySourceWebServerAppHostConfigDirectory)</WebServerAppHostConfigDirectory>
        <WebServerManifest>$(_MSDeploySourceWebServerManifest)</WebServerManifest>
        <WebServerDirectory>$(_MSDeploySourceWebServerDirectory)</WebServerDirectory>
      </_AoPubAppOfflineSourceProviderSetting>

      <_AoPubAppOfflineDestProviderSetting Include="contentPath">
        <Path>"$(DeployIisAppPath)/app_offline.htm"</Path>
        <ComputerName>$(_PublishMsDeployServiceUrl)</ComputerName>
        <UserName>$(UserName)</UserName>
        <Password>$(Password)</Password>
        <EncryptPassword>$(DeployEncryptKey)</EncryptPassword>
        <IncludeAcls>False</IncludeAcls>
        <AuthType>$(AuthType)</AuthType>
        <WebServerAppHostConfigDirectory>$(_MSDeployDestinationWebServerAppHostConfigDirectory)</WebServerAppHostConfigDirectory>
        <WebServerManifest>$(_MSDeployDestinationWebServerManifest)</WebServerManifest>
        <WebServerDirectory>$(_MSDeployDestinationWebServerDirectory)</WebServerDirectory>
      </_AoPubAppOfflineDestProviderSetting>
    </ItemGroup>

    <MSdeploy
          MSDeployVersionsToTry="$(_MSDeployVersionsToTry)"
          Verb="sync"
          Source="@(_AoPubAppOfflineSourceProviderSetting)"
          Destination="@(_AoPubAppOfflineDestProviderSetting)"
          EnableRule="DoNotDeleteRule"
          AllowUntrusted="$(AllowUntrustedCertificate)"
          RetryAttempts="$(RetryAttemptsForDeployment)"
          SimpleSetParameterItems="@(_AoArchivePublishSetParam)"
          ExePath="$(MSDeployPath)" />
  </Target>

  <!--***********************************************************************
  Make sure app_offline-template.htm gets published as app_offline.htm
  ***************************************************************************-->
  <!-- We need to create a replace rule for app_offline-template.htm->app_offline.htm for when the app get's published -->
  <ItemGroup>
    <!-- Make sure not to include this file if a package is being created, so condition this on publishing -->
    <FilesForPackagingFromProject Include="app_offline-template.htm" Condition=" '$(DeployTarget)'=='MSDeployPublish' ">
      <DestinationRelativePath>app_offline.htm</DestinationRelativePath>
    </FilesForPackagingFromProject>

    <!-- This will prevent app_offline-template.htm from being published -->
    <MsDeploySkipRules Include="SkipAppOfflineTemplate">
      <ObjectName>filePath</ObjectName>
      <AbsolutePath>app_offline-template.htm</AbsolutePath>
    </MsDeploySkipRules>
  </ItemGroup>

  <!--***********************************************************************
  When publish is completed we need to delete the app_offline.htm
  ***************************************************************************-->
  <Target Name="DeleteAppOffline" AfterTargets="MSDeployPublish">
    <!--
    %msdeploy% 
      -verb:delete 
      -dest:contentPath="{IIS-Path}/app_offline.htm",computerName="...",username="...",password="..."
    -->
    <Message Text="************************************************************************" />
    <Message Text="Calling MSDeploy to delete the app_offline.htm file" Importance="high" />
    <Message Text="************************************************************************" />

    <ItemGroup>
      <_AoDeleteAppOfflineDestProviderSetting Include="contentPath">
        <Path>$(DeployIisAppPath)/app_offline.htm</Path>
        <ComputerName>$(_PublishMsDeployServiceUrl)</ComputerName>
        <UserName>$(UserName)</UserName>
        <Password>$(Password)</Password>
        <EncryptPassword>$(DeployEncryptKey)</EncryptPassword>
        <AuthType>$(AuthType)</AuthType>
        <WebServerAppHostConfigDirectory>$(_MSDeployDestinationWebServerAppHostConfigDirectory)</WebServerAppHostConfigDirectory>
        <WebServerManifest>$(_MSDeployDestinationWebServerManifest)</WebServerManifest>
        <WebServerDirectory>$(_MSDeployDestinationWebServerDirectory)</WebServerDirectory>
      </_AoDeleteAppOfflineDestProviderSetting>
    </ItemGroup>
    
    <!-- 
    We cannot use the MSDeploy/VSMSDeploy tasks for delete so we have to call msdeploy.exe directly.
    When they support delete we can just pass in @(_AoDeleteAppOfflineDestProviderSetting) as the dest
    -->
    <PropertyGroup>
      <_Cmd>"$(MSDeployExe)" -verb:delete -dest:contentPath="%(_AoDeleteAppOfflineDestProviderSetting.Path)"</_Cmd>
      <_Cmd Condition=" '%(_AoDeleteAppOfflineDestProviderSetting.ComputerName)' != '' ">$(_Cmd),computerName="%(_AoDeleteAppOfflineDestProviderSetting.ComputerName)"</_Cmd>
      <_Cmd Condition=" '%(_AoDeleteAppOfflineDestProviderSetting.UserName)' != '' ">$(_Cmd),username="%(_AoDeleteAppOfflineDestProviderSetting.UserName)"</_Cmd>
      <_Cmd Condition=" '%(_AoDeleteAppOfflineDestProviderSetting.Password)' != ''">$(_Cmd),password=$(Password)</_Cmd>
      <_Cmd Condition=" '%(_AoDeleteAppOfflineDestProviderSetting.AuthType)' != ''">$(_Cmd),authType="%(_AoDeleteAppOfflineDestProviderSetting.AuthType)"</_Cmd>
    </PropertyGroup>

    <Exec Command="$(_Cmd)"/>
  </Target>  
</Project>

#1 Publish app_offline.htm

The implementation for #1 is contained inside the target PublishAppOfflineToDest. The msdeploy.exe command that we need to get executed is.

msdeploy.exe
    -source:contentPath='C:\Data\Personal\My Repo\sayed-samples\AppOfflineDemo01\AppOfflineDemo01\app_offline-template.htm'
    -dest:contentPath='"Default Web Site/AppOfflineDemo/app_offline.htm"',UserName='sayedha',Password='password-here',ComputerName='computername-here',IncludeAcls='False',AuthType='NTLM' -verb:sync -enableRule:DoNotDeleteRule

In order to do this I will leverage the MSDeploy task. Inside of the PublishAppOfflineToDest target you can see how this is accomplished by creating an item for both the source and destination.

#2 Publish the app, and ensure that app_offline.htm is contained inside the payload being published

This part is accomplished by the fragment

  <!--***********************************************************************
  Make sure app_offline-template.htm gets published as app_offline.htm
  ***************************************************************************-->
  <!-- We need to create a replace rule for app_offline-template.htm->app_offline.htm for when the app get's published -->
  <ItemGroup>
    <!-- Make sure not to include this file if a package is being created, so condition this on publishing -->
    <FilesForPackagingFromProject Include="app_offline-template.htm" Condition=" '$(DeployTarget)'=='MSDeployPublish' ">
      <DestinationRelativePath>app_offline.htm</DestinationRelativePath>
    </FilesForPackagingFromProject>

    <!-- This will prevent app_offline-template.htm from being published -->
    <MsDeploySkipRules Include="SkipAppOfflineTemplate">
      <ObjectName>filePath</ObjectName>
      <AbsolutePath>app_offline-template.htm</AbsolutePath>
    </MsDeploySkipRules>
  </ItemGroup>

The item value for FilesForPackagingFromProject here will convert your app_offline-template.htm to app_offline.htm in the folder from where the publish will be processed. Also there is a condition on it so that it only happens during publish and not packaging. We do not want app_offline-template.htm to be in the package (but it’s not the end of the world if it does either).

The element for MsDeploySkiprules will make sure that app_offline-template.htm itself doesn’t get published. This may not be required but it shouldn’t hurt.

#3 Delete app_offline.htm

Now that our app is published we need to delete the app_offline.htm file from the dest web app. The msdeploy.exe command would be:

%msdeploy%
      -verb:delete
      -dest:contentPath="{IIS-Path}/app_offline.htm",computerName="...",username="...",password="..."

This is implemented inside of the DeleteAppOffline target. This target will automatically get executed after the publish because I have included the attribute AfterTargets=”MSDeployPublish”. In that target you can see that I am building up the msdeploy.exe command directly, it looks like the MSDeploy task doesn’t support the delete verb.

If you do try this out please let me know if you run into any issues. I am thinking to create a Nuget package from this so that you can just install that package. That would take a bit of work so please let me know if you are interested in that.

Resources

  1. The latest version of my AppOffline wpp.targets file.
  2. ScottGu’s blog on app_offline.htm

 

Sayed Ibrahim Hashimi @SayedIHashimi

IIS | Microsoft | msbuild | MSDeploy | Visual Studio 2010 | web | Web Deployment Tool | Web Publishing Pipeline Sunday, January 08, 2012 8:44:39 PM (GMT Standard Time, UTC+00:00)  #     | 
Tuesday, November 08, 2011

Using a Web Deploy package to deploy to IIS on the dev box and to a third party host

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:

The Package/Publish Web tab now looks like this:

Package_Publish_Web_tab_Test

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.

Package_Publish_Web_tab_Release

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.

Solution_Configurations_dropdown

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.

Output_Window_package_creation

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.)

Default_Web_Site_in_inetmgr

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.)

Select_the_Package_dialog_box

Click Next. The Select the Contents of the Package step is displayed.

Select_the_Contents_of_the_Package_dialog_box

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.

Enter_Application_Package_Information_dialog_box

Click Next.

The wizard asks if you want to delete files at the destination that aren't in the source.

Overwrite_Existing_Files_dialog_box

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.

Installation_Progress_and_Summary_dialog_box

Click Finish.

Open a browser and run the application in test by going to the URL http://localhost/ContosoUniversity.

Instructors_page_with_separate_name_fields_Test

Installing IIS Manager for Remote Administration

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:

Connecting to Your Site at the Hosting Provider

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.)

IIS_Manager_Remote_Admin_Start_Page

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.

Specify_Site_Connection_Details_dialog_box

In the Provide Credentials step, enter the user name and password assigned by the provider, and then click Next:

Provide_Credentials_dialog_box

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.

Server_Certificate_Alert_dialog_box

In the Specify a Connection Name step, click Finish.

Specify_a_Connection_Name_dialog_box

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.

New_Feature_Available_dialog_box_Cytanium

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.

Solution_Configurations_dropdown_Release

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 Manager Connections 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.

IIS_Manager_with_provider_site_selected

In the Select the Package step, select the package that you just created:

Select_the_Package_dialog_box_Prod

In the Select the Contents of the Package step, leave all the check boxes selected and click Next:

Select_the_Contents_of_the_Package_dialog_box_Prod

In the Enter Application Package Information step, clear the Application Path and click Next:

Enter_Application_Package_Information_dialog_box_Prod

The wizard asks if you want to delete files at the destination that aren't in the source.

Overwrite_Existing_Files_dialog_box

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:

Installation_in_root_folder_warning

Package installation begins. When it's done, the Installation Progress and Summary dialog box is shown:

Installation_Progress_and_Summary_dialog_box

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.

Instructors_page_with_separate_name_fields_Prod

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.

Sayed Ibrahim Hashimi – @SayedIHashimi

ddd

IIS | msbuild | MSDeploy | web | Web Deployment Tool | Web Development | Web Publishing Pipeline Tuesday, November 08, 2011 5:11:43 AM (GMT Standard Time, UTC+00:00)  #     | 
Friday, February 25, 2011

How to compress CSS/JavaScript before publish/package

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.



  

  
  
    
    
      <_JavaScriptFiles Include="$(_PackageTempDir)\Scripts\**\*.js" />
      <_CssFiles Include="$(_PackageTempDir)\Content\**\*.css" />
    

    
    
    

    
    
    
  

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.

1. Gather files to be compressed

  <_JavaScriptFiles Include="$(_PackageTempDir)\Scripts\**\*.js" />
  <_CssFiles Include="$(_PackageTempDir)\Content\**\*.css" />

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.

image

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.

Sayed Ibrahim Hashimi

Resources
Deployment | MSDeploy | Web Publishing Pipeline Friday, February 25, 2011 5:21:44 AM (GMT Standard Time, UTC+00:00)  #     | 
Saturday, January 08, 2011

Video on Web Deployment using Visual Studio 2010 and MSDeploy

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:

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!

Sayed Ibrahim Hashimi @sayedihashimi

Config-Transformation | IIS | msbuild | MSDeploy | speaking | Visual Studio | Visual Studio 2010 | web | Web Deployment Tool | Web Development | Web Publishing Pipeline Saturday, January 08, 2011 8:34:08 PM (GMT Standard Time, UTC+00:00)  #     | 
Thursday, November 18, 2010

XDT (web.config) Transforms in non-web projects

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:

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)

image

The files with .debug/.release are transform files. When I build I expect the following to happen:

  1. 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
  2. Transform Sample01.xml with Sample01.{Configuration}.config and write it to output folder with the name Sample01.config
  3. 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
  4. 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 Smile

  1. You must have installed Web projects with Visual Studio on the machine (it contains the TransformXmll task).
  2. 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.
  3. Download TransformFiles.targets (link below) and place the file into the folder %ProgramFiles (x86)%\MSBuild\Custom.
  4. Edit your project file (right click on the project Unload Project, right click again and pick edit)
  5. At the end of the project file place the element <Import Project="$(MSBuildExtensionsPath)\Custom\TransformFiles.targets" /> immediately above the closing </Project> tag
  6. For files that you want transformed a metadata value of TransformOnBuild to true. See below on what this means.
  7. 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.

<None Include="app.config">
  <TransformOnBuild>true</TransformOnBuild>
</None>

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.

<None Include="app.debug.config">
  <DependentUpon>app.config</DependentUpon>
</None>
<None Include="app.release.config">
  <DependentUpon>app.config</DependentUpon>
</None>

Implementation

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.

Resources

Sayed Ibrahim Hashimi @sayedihashimi

msbuild | MSBuild 4.0 | MSDeploy | Web Publishing Pipeline Thursday, November 18, 2010 5:41:09 AM (GMT Standard Time, UTC+00:00)  #     | 
Thursday, November 11, 2010

ASP.NET Web Application: Publish/Package Tokenizing Parameters

Today I just saw a question posted on stackoverflow.com asking Why are some Web.config transforms tokenised into SetParameters.xml and others are not? Let me give some background on this topic for those who are not aware of what the question is.

With Visual Studio 2010 when you package your application using the Build Deployment Package context menu option, see image below.

image

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.

image

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.

SNAGHTML2d2664

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.

<configuration>
  <appSettings>
    <add key="setting01" value="value01"/>
  </appSettings>
  
  <connectionStrings>
    <add name="ApplicationServices"
         connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true"
         providerName="System.Data.SqlClient" />
  </connectionStrings>
  
</configuration>

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.

<configuration>
  <appSettings>
    <add key="setting01" value="value01"/>
  </appSettings>
  <connectionStrings>
    <add name="ApplicationServices"
         connectionString="$(ReplacableToken_ApplicationServices-Web.config Connection String_0)"
         providerName="System.Data.SqlClient" />
  </connectionStrings>

</configuration>

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.

<?xml version="1.0" encoding="utf-8"?>
<parameters>
  <setParameter name="IIS Web Application Name" 
                value="Default Web Site/MvcApplication1_deploy" />
  <setParameter name="ApplicationServices-Web.config Connection String" 
                value="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true" />
</parameters>

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.

Questions/Comments???

Other Resources

asp.net | Deployment | msbuild | MSBuild 4.0 | MSDeploy Thursday, November 11, 2010 5:41:09 AM (GMT Standard Time, UTC+00:00)  #     | 
Thursday, November 04, 2010

Web Deploy: How to see the command executed in Visual Studio during publish

I just saw a post on twitter asking the question

Is there any easy way to see the underlying MSBuild command when building in VS2010? Want to see the MSDeploy params. @wdeploy?

This is actually pretty easy, but wouldn’t fit into 140 characters, so I decided to blog it.

One thing to know is that when you publish from Visual Studio, by default we use the MSDeploy (AKA Web Deployment Tool) Object Model in order to perform the deployment. We do this for performance and other reasons. Because of this there is no real msdeploy.exe command that is being issued. You can however change that behavior. This is controlled by an MSBuild property UseMSDeployExe which is false by default. In this case since Troy wants to see the command we will need to set that property to false. There are 2 ways in which you can do this. You can set it in the project file itself, or you can define it in a .wpp.targets file. I would recommend the second approach. What you need to do is to create a file with the name {ProjectName}.wpp.targets in the same directory as the project where {ProjectName} is the name of the Web Application Project (WAP). When you do this, during a build or publish the file is automatically imported into the build process. In my example I have a WAP named WebApplication1.csproj, so I created the file WebApplication1.wpp.targets and its contents are shown below.

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" 
         xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <UseMsdeployExe>true</UseMsdeployExe>
  </PropertyGroup>
</Project>

In the snippet above you can see that I defined the property to true. Now there is one more thing to do, publish the project. Once you publish the project, in the output window you will see the MSDeploy command which is being used. In my case I published the project to localhost to the Default Web Site/Test01 application path. You may have to copy the text from the output window into Notepad and search for msdeploy.exe. The command that was issued in my case is shown below (with formatting changes for readability).

"C:\Program Files (x86)\IIS\Microsoft Web Deploy\msdeploy.exe" 
-source:manifest='C:\temp\_NET\ThrowAway\WebApplication3\WebApplication1\obj\Debug\Package\WebApplication1.SourceManifest.xml' 
-dest:auto,IncludeAcls='False',AuthType='NTLM' 
-verb:sync 
-enableRule:DoNotDeleteRule 
-disableLink:AppPoolExtension 
-disableLink:ContentExtension 
-disableLink:CertificateExtension 
-setParam:kind='ProviderPath',
    scope='IisApp',match='^C:\\temp\\_NET\\ThrowAway\\WebApplication3\\WebApplication1\\obj\\Debug\\Package\\PackageTmp$',
    value='Default Web Site/Test01' 
-setParam:kind='ProviderPath',
    scope='setAcl',
    match='^C:\\temp\\_NET\\ThrowAway\\WebApplication3\\WebApplication1\\obj\\Debug\\Package\\PackageTmp$',
    value='Default Web Site/Test01' 
-retryAttempts=2 

So that’s it, pretty simple.

FYI, if you want more detail you can increase the MSBuild Output Window verbosity by going to Tools->Options->Projects and Solutions->Build and Run then specifying a different value for MSBuild project build output verbosity.

Sayed Ibrahim Hashimi - @sayedihashimi

msbuild | MSDeploy | Web Deployment Tool | Web Development Thursday, November 04, 2010 4:03:26 AM (GMT Standard Time, UTC+00:00)  #     | 
Thursday, October 21, 2010

ASP.NET Web Projects: web.debug.config & web.release.config

Warning: What you see below feels hacky to me, but if you find it useful then use it

I have heard a lot of questions and confusion regarding web.debug.config and web.release.config. For example here is just one question on StackOverflow. The question states:

Hello, I want to use the web.config transformation that works fine for publish also for debugging.

When i publish a web app, visual studio automatically transforms the web.config based on my 
current build configuration. How can i tell visual studio 
to do the same when i start debugging. On debug start it simply 
uses the default web.config without transformation.

Any idea?

First let me explain, as I did to that question, the purpose of the files: web.config/web.debug.config/web.release.config.

web.config

This is the config file which developers should use locally. Ideally you should get this to be standardized. For instance you could use localhost for DB strings, and what not. You should strive for this to work on dev machines without changes.

web.debug.config

This is the transform that is applied when you publish your application to the development staging environment. This would make changes to the web.config which are required for the target environment.

web.release.config

This is the transform that is applied when you publish your application to the "production" environment. Obviously you'll have to be careful with passwords depending on your application/team.

The problem with transforming the web.config that you are currently running is that a transform can perform destructive actions to the web.config. For example it may delete a attributes, delete elements, etc.

Resolution

Ok, with that out the way not let’s see how we can enable what the question asker wants to do. To recap, when he builds on a particular configuration he wants a specific transform to be applied to web.config. So obviously you do not want to maintain a web.config file, because it is going to be overwritten. So what we need to do is to create a new file web.template.config, which is just a copy of web.config. Then just delete web.config by using Windows Explorer (don’t delete using Visual Studio because we do not want to delete it from the project). Note: If you are using a source control provider which is integrated into Visual Studio then you probably want to delete web.config from source control. Also with this we do not want to use web.debug.config or web.release.config because these already have a well defined role in the Web Publishing Pipeline so we do not want to disturb that. So instead we will create two new files, in the same folder as the project and web.template.config, web.dev.debug.config and web.dev.release.config. The ideas is that these will be the transforms applied when you debug, or run, your application from Visual Studio. Now we need to hook into the build/package/publish process to get this all wired up. With Web Application Projects (WAP) there is an extensibility point that you can create a project file in the same folder with the name {ProjectName}.wpp.targets where {ProjectName} is the name of the project. If this file is on disk in the same folder as the WAP then it will automatically be imported into the project file. So I have created this file. And I have placed the following content:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <!-- Make sure web.config will be there even for package/publish -->
  <Target Name="CopyWebTemplateConfig" BeforeTargets="Build">
    <Copy SourceFiles="web.template.config"
          DestinationFiles="web.config"/>
  </Target>
  
  <PropertyGroup>
    <PrepareForRunDependsOn>
      $(PrepareForRunDependsOn);
      UpdateWebConfigBeforeRun;
    </PrepareForRunDependsOn>
  </PropertyGroup>

  <!-- This target will run right before you run your app in Visual Studio -->
  <Target Name="UpdateWebConfigBeforeRun">
    <Message Text="Configuration: $(Configuration): web.dev.$(Configuration).config"/>
    <TransformXml Source="web.template.config"
              Transform="web.dev.$(Configuration).config"
              Destination="web.config" />
  </Target>

  <!-- Exclude the config template files from the created package -->
  <Target Name="ExcludeCustomConfigTransformFiles" BeforeTargets="ExcludeFilesFromPackage">
    <ItemGroup>
      <ExcludeFromPackageFiles Include="web.template.config;web.dev.*.config"/>
    </ItemGroup>
    <Message Text="ExcludeFromPackageFiles: @(ExcludeFromPackageFiles)" Importance="high"/>
  </Target>
</Project>

Let me explain this a bit. I have created the CopyWebTemplateConfig target which will always copy web.template.config to web.config on build, even if you are not debugging your application in Visual Studio. This is needed because we still need to support the package/publish process of Visual Studio. Then I extended the property PrepareForRunDependsOn to include the UpdateWebConfigBeforeRun target. This property is used to identify the list of targets which needs to be executed before any managed project is run from Visual Studio. In this target I am using the TransformXml task to transform web.template.config, using the correct web.dev.***.config file. After that your app starts up using the correct web.config based on  your build configuration.

After that I have another target ExcludeCustomConfigTransformsFiles, which I inject into the package/publish process via the attribute BeforeTargets=”ExcludeFilesFromPackage”. This is needed because we do not want these files to be included when the application is packaged or published.

So that is really all there is to it. To explain the package/publish process a bit more for this scenario. When you package/publish web.debug.config or web.release.config, depending on build configuration, will still be used. But ultimately the file that it is transforming is web.template.config, so you may have to adjust depending on what you have in that file. Questions/Comments?

Sayed Ibrahim Hashimi - @sayedihashimi

msbuild | MSDeploy | Web Publishing Pipeline Thursday, October 21, 2010 7:13:26 AM (GMT Daylight Time, UTC+01:00)  #     | 
Thursday, September 09, 2010

Extending XML (web.config) Config transformation

Last week on StackOverflow I answered a question, Make web.config transformations working locally and in a response to my answer the question asker asked me if I would be able to a question he posed earlier Advanced tasks using web.config transformation. Evidently he is really interested in config transformations! I don’t blame him, I’m really into them as well.

In his question he asks (summarizing) can we replace portions of attribute values instead of this entire attribute? So for instance you have the following in your web.config. Below is two sets of appSettings one from Dev and the other from Prod (taken from the original question).

<!-- DEV ENTRY -->
<appSettings>
 <add key="serviceName1_WebsService_Url" value="http://wsServiceName1.dev.domain.com/v1.2.3.4/entryPoint.asmx" />
 <add key="serviceName2_WebsService_Url" value="http://ma1-lab.lab1.domain.com/v1.2.3.4/entryPoint.asmx" />
</appSettings>

<!-- PROD ENTRY -->
<appSettings>
 <add key="serviceName1_WebsService_Url" value="http://wsServiceName1.prod.domain.com/v1.2.3.4/entryPoint.asmx" />
 <add key="serviceName2_WebsService_Url" value="http://ws.ServiceName2.domain.com/v1.2.3.4/entryPoint.asmx" />
</appSettings>

In the above we just want to replace dev with prod and ma1-lab.lab1.domain with ws.ServiceName2.domain. For those wondering currently we have the following transformations out of the box.

At the end of this article I’ve linked to another blog which has more info about these transformations. So it sounds like SetAttributes is almost what we want, but not quite what there. A little known fact is that you can create your own config transformations and use those. In fact all of the out of the box transformations follow the same patterns that custom transformations would. To solve this issue we need to create our own config transformation, AttributeRegexReplace. This transformation will take an attribute value and do a regular expression replace on its value. In order to create a new transformation you first reference the Microsoft.Web.Publishing.Tasks.dll which can be found in the %Program Files (x86)%MSBuild\Microsoft\VisualStudio\v10.0\Web folder. If you are working with a team it is best if you copy that assembly, place it in a shared folder in source control, and make the reference from that location. After you create the reference to that assembly you will need to create a class which extends the Transform class. The class diagram for this abstract class is shown below.

image

The only thing that you will need to implement is the Apply method. You don’t even need to fully understand all of the properties and methods just the portions that you are interested in. Here we will not cover all the details of this class, or other related classes which exist, but there will be future posts which will shed more light on this area.

In the sample class library that I created, I called the project CustomTransformType. Inside of that project I created the class AttributeRegexReplace. The entire contents of that class are shown below, we will go over the details after that.

namespace CustomTransformType
{
    using System;
    using System.Text.RegularExpressions;
    using System.Xml;
    using Microsoft.Web.Publishing.Tasks;

    public class AttributeRegexReplace : Transform
    {
        private string pattern;
        private string replacement;
        private string attributeName;

        protected string AttributeName
        {
            get
            {
                if (this.attributeName == null)
                {
                    this.attributeName = this.GetArgumentValue("Attribute");
                }
                return this.attributeName;
            }
        }
        protected string Pattern
        {
            get
            {
                if (this.pattern == null)
                {
                    this.pattern = this.GetArgumentValue("Pattern");
                }

                return pattern;
            }
        }

        protected string Replacement
        {
            get
            {
                if (this.replacement == null)
                {
                    this.replacement = this.GetArgumentValue("Replacement");
                }

                return replacement;
            }
        }

        protected string GetArgumentValue(string name)
        {
            // this extracts a value from the arguments provided
            if (string.IsNullOrWhiteSpace(name)) 
            { throw new ArgumentNullException("name"); }

            string result = null;
            if (this.Arguments != null && this.Arguments.Count > 0)
            {
                foreach (string arg in this.Arguments)
                {
                    if (!string.IsNullOrWhiteSpace(arg))
                    {
                        string trimmedArg = arg.Trim();
                        if (trimmedArg.ToUpperInvariant().StartsWith(name.ToUpperInvariant()))
                        {
                            int start = arg.IndexOf('\'');
                            int last = arg.LastIndexOf('\'');
                            if (start <= 0 || last <= 0 || last <= 0)
                            {
                                throw new ArgumentException("Expected two ['] characters");
                            }

                            string value = trimmedArg.Substring(start, last - start);
                            if (value != null)
                            {
                                // remove any leading or trailing '
                                value = value.Trim().TrimStart('\'').TrimStart('\'');
                            }
                            result = value;
                        }
                    }
                }
            }
            return result;
        }

        protected override void Apply()
        {
            foreach (XmlAttribute att in this.TargetNode.Attributes)
            {
                if (string.Compare(att.Name, this.AttributeName, StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    // get current value, perform the Regex
                    att.Value = Regex.Replace(att.Value, this.Pattern, this.Replacement);
                }
            }
        }
    }
}

In this class we have 3 properties; Pattern, Replacement, and AttributeName. All of these values will be provided via an argument in the config transformation. For example take a look at the element below which contains a transform attribute may look like the following.

<add key="two" value="two-replaced" 
         xdt:Transform="AttributeRegexReplace(Attribute='value', Pattern='here',Replacement='REPLACED')" 
         xdt:Locator="Match(key)"/>

In this example I declare that I am using AttributeRegexReplace and then specify the values for the attributes within the (). In the class above I have a method, GetArgumentValue, which is used to parse values from that argument string. When your transform is invoked the string inside of () is passed in as the ArgumentString value. If you are using a , as the argument separator, as I am, then you can use the Arguments list. Which will split up the arguments by the , character. Surprisingly in the 101 lines of code in the sample there are only a few interesting lines. Those are what’s contained inside the Apply method. Inside that method I search the TargetNode’s attributes (TargetNode is the node which was matched in the xml file being transformed) for an attribute with the same name as the one specified in the AttributeName property. Once I find it I just make a call to Regex.Replace to get the new value, and assign it. Pretty simple! Now lets see how can we use this.

Let’s say you have the following very simple web.config

<?xml version="1.0"?>
<configuration>
  <appSettings>
    <add key="one" value="one"/>
    <add key="two" value="partial-replace-here-end"/>
    <add key="three" value="three here"/>
  </appSettings>
</configuration>

If we want to be able to use our own transform then we will have to use the xdt:Import element. You can place that element inside the xml document anywhere immediately under the root element. This element will allow us to utilize our own transform class. It only has 3 possible attributes.

You can only use one of the two; path and assembly. Basically it boils down to how the assembly is loaded. If you use path the assembly will be loaded with Assembly.LoadFrom and if you chose to use assembly passing in the AssemblyName, for instance if the assembly in in the GAC, then it will be loaded using Assembly.Load.

I chose to use path, because I just placed the file inside of the MSBuild Extensions directory (%Program Files (x86)%MSBuild) in a folder named Custom. Then I created my config transform file to be the following.

<?xml version="1.0"?>

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
                        
  <xdt:Import path="C:\Program Files (x86)\MSBuild\Custom\CustomTransformType.dll"
              namespace="CustomTransformType" />

  <appSettings>
    <add key="one" value="one-replaced" xdt:Transform="Replace" xdt:Locator="Match(key)" />
    <add key="two" value="two-replaced" xdt:Transform="AttributeRegexReplace(Attribute='value', Pattern='here',Replacement='REPLACED')" xdt:Locator="Match(key)"/>
  </appSettings>
</configuration>

Then to run this I created an MSBuild file, PerformTransform.proj, which is shown below.

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Demo" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <UsingTask TaskName="TransformXml"
           AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll"/>

  <PropertyGroup>
    <TransformDest>web.tranzed.config</TransformDest>
  </PropertyGroup>
  
  <Target Name="Demo">
    <Delete Files="$(TransformDest)" />
    <TransformXml Source="web.config"
                  Transform="web.dev.config"
                  Destination="$(TransformDest)" />                  
  </Target>
  
</Project>

This file uses the TransformXml task as I outlined in a previous post Config transformations outside of web app builds. Once you execute the Demo target with the command msbuild PerformTransform.proj /t:Demo you will see the file web.tranzed.config with the following contents.

<?xml version="1.0"?>
<configuration>
  <appSettings>
    <add key="one" value="one-replaced"/>
    <add key="two" value="partial-replace-REPLACED-end"/>
    <add key="three" value="three here"/>
  </appSettings>
</configuration>

So you can see that the replacement did occur as we intended. Below you will find the download link for the samples as well as another blog entry for more info on the out of the box transformations.

Resources

Sayed Ibrahim Hashimi

Config-Transformation | msbuild | MSDeploy Thursday, September 09, 2010 6:51:43 AM (GMT Daylight Time, UTC+01:00)  #     | 
Sunday, August 15, 2010

Web Deployment Tool (MSDeploy): How to exclude files from package based on Configuration

A while back I posted an entry on How to build a package including extra files or exclude files a reader posted a question to StackOverflow.com asking how to exclude files from the created package based on the configuration for the project. He asked me to take a look at it so I figured it would be a good blog post.

From the previous post we can see that the way to exclude files from packaging is by declaring an item as follows.

<ItemGroup>
  <ExcludeFromPackageFiles Include="Sample.Debug.xml">
    <FromTarget>Project</FromTarget>
  </ExcludeFromPackageFiles>
</ItemGroup>

So we need to extend this to only exclude files if the config is a certain value. Since MSBuild supports conditions on almost every element this is going to be a breeze. As an example I have created a sample web project with a scripts directory that has the following files.

image

In that folder there I there are two files which have ‘debug’ in the name of the file. We only want those to be included if the configuration is set to Debug, or another way of putting it is we want to exclude those files if the configuration is not Debug. So we need to create to add files to the ExcludeFromPackageFiles and guard it with the condition that the configuration is not debug. Here is that.

<Target Name="CustomExlucdeFiles" BeforeTargets="ExcludeFilesFromPackage">
  <ItemGroup Condition=" '$(Configuration)'!='Debug' ">
    <ExcludeFromPackageFiles Include="scripts\**\*debug*" />
  </ItemGroup>
  
  <Message Text="Configuration: $(Configuration)" />
  <Message Text="ExcludeFromPackageFiles: @(ExcludeFromPackageFiles)" Importance="high" />
</Target>

You can see the item group defined above which does what we want. Please note that I put this inside of a target, CustomExcludeFiles, I will discuss why in a bit but let’s stay on topic now. So this is pretty straight forward when the item group is evaluated all files under scripts which have debug in the file name will be excluded if the configuration is not set to Debug. Let’s see if it works, I will build the deployment package once in both debug & release then examine the contents of the Package folder.

image

So we can see that the files were excluded from the Release package. Now back to why I declared the item group in a target instead of directly in the project file itself. I noticed that if I declare that item in the project file there are some visual issues with the representation in the Solution Explorer. To be specific the files show up as dups, see image below.

image

I have reported this to the right people, but for now this is a harmless issue with an easy workaround.

Sayed Ibrahim Hashimi

Deployment | msbuild | MSDeploy | Web Deployment Tool | Web Publishing Pipeline Sunday, August 15, 2010 7:56:50 PM (GMT Daylight Time, UTC+01:00)  #     | 
Monday, June 07, 2010

Installing web apps made easy: Web Platform Installer

If you are doing any kind of web development and you are not familiar with the Web Platform Installer(WPI) then you need to take a look at it. I just installed WordPress on IIS 7 with just a few clicks and  filled in a few text boxes. When you install WordPress there are some prerequisites like mySql and php. The WPI was smart enough to realize that I had neither installed, downloaded those, installed them and configured them. I was prompted for some info for those tools of course. I’ve also installed a few other apps using the WPI like, MSDeploy and dasBlog and I didn’t have any issues what so ever.

When using the WPI there are two main categories that can be installed, Web Platform and Web Applications. The Web Platform category includes items like frameworks (i.e. ASP.NET, PHP), Database (i.e. mySql) and other high level shared components. The Web Applications includes various web applications. Some others that I didn’t list previously include; DotNetNuke, nopCommerce, and umbarco just to name a few. I’m not sure how many apps are available but it looks like at least 50.

If you are an app creator and would like to share your app then you can visit the WPI Developer page for a starting point.

Deployment | IIS | MSDeploy | web | Web Platform Installer Monday, June 07, 2010 4:17:01 AM (GMT Daylight Time, UTC+01:00)  #     | 
Saturday, May 01, 2010

Web Deployment Tool (MSDeploy) : Build Package including extra files or excluding specific files

If you are using Visual Studio 2010 then you may already be aware that Web Deployment Tool (aka MSDeploy) is integrated into Visual Studio. I’ve posted a few blog entries already about this tool. Two of the common questions that I get discussing this with people are

  1. How do I exclude files from being placed in the package?
  2. How do I add other files to the created package?

I will address these two questions here, first we look at the easier one, how to exclude files but we will go over a bit of background first.

Web Publishing Pipeline

With Visual Studio 2010 a new concept has been created which is known as the Web Publishing Pipeline. In a nutshell this is a process which will take your web application, build it and eventually create a package that you can use to deploy your application. This process is fully captured in MSBuild. With VS 2010 many targets and many tasks are shipped to support this process. Since its captured in MSBuild format, you can customize and extend to your hearts desire. So what we need to do is hook into this process to perform the customizations that we need. This process is captured in the following files.

%program files%\MSBuild\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets
%program files%\MSBuild\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.targets

The Microsoft.WebApplication.targets file is imported by the web applications projects file, then that file imports the Microsoft.Web.Publishing.targets file.

Excluding files from being packaged

If you open the project file of a web application created with VS 2010 towards the bottom of it you will find a line with.

<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />

BTW you can open the project file inside of VS. Right click on the project pick Unload Project. Then right click on the unloaded project and select Edit Project.

This statement will include all the targets and tasks that we need. Most of our customizations should be after that import, if you are not sure put if after! So if you have files to exclude there is an item name, ExcludeFromPackageFiles, that can be used to do so. For example let’s say that you have file named Sample.Debug.js which included in your web application but you want that file to be excluded from the created packages. You can place the snippet below after that import statement.

<ItemGroup>
  <ExcludeFromPackageFiles Include="Sample.Debug.xml">
    <FromTarget>Project</FromTarget>
  </ExcludeFromPackageFiles>
</ItemGroup>

By declaring populating this item the files will automatically be excluded. Note the usage of the FromTarget metadata here. I will not get into that here, but you should know to always specify that.

Including extra files into the package

Including extra files into the package is a bit harder but still no bigee if you are comfortable with MSBuild, and if you are not then read this.  In order to do this we need to hook into the part of the process that collects the files for packaging. The target we need to extend is called CopyAllFilesToSingleFolder. This target has a dependency property, PipelinePreDeployCopyAllFilesToOneFolderDependsOn, that we can tap into and inject our own target. So we will create a target named CustomCollectFiles and inject that into the process. We achieve this with the following (remember after the import statement).

<PropertyGroup>
  <CopyAllFilesToSingleFolderForPackageDependsOn>
    CustomCollectFiles;
    $(CopyAllFilesToSingleFolderForPackageDependsOn);
  </CopyAllFilesToSingleFolderForPackageDependsOn>
</PropertyGroup>

This will add our target to the process, now we need to define the target itself. Let’s assume that you have a folder named Extra Files that sits 1 level above your web project. You want to include all of those files. Here is the CustomCollectFiles target and we discuss after that.

<Target Name="CustomCollectFiles">
  <ItemGroup>
    <_CustomFiles Include="..\Extra Files\**\*" />

    <FilesForPackagingFromProject  Include="%(_CustomFiles.Identity)">
      <DestinationRelativePath>Extra Files\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
    </FilesForPackagingFromProject>
  </ItemGroup>
</Target>

Here what I did was create the item _CustomFiles and in the Include attribute told it to pick up all the files in that folder and any folder underneath it. Then I use this item to populate the FilesForPackagingFromProject item. This is the item that MSDeploy actually uses to add extra files. Also notice that I declared the metadata DestinationRelativePath value. This will determine the relative path that it will be placed in the package. I used the statement Extra Files%(RecursiveDir)%(Filename)%(Extension) here. What that is saying is to place it in the same relative location in the package as it is under the Extra Files folder.

Admittedly this could be easier, but its not too bad, and its pretty flexible.

Sayed Ibrahim Hashimi

msbuild | MSBuild 4.0 | MSDeploy | Visual Studio | Visual Studio 2010 | Web Deployment Tool | Web Publishing Pipeline Saturday, May 01, 2010 4:09:16 AM (GMT Daylight Time, UTC+01:00)  #     | 
Monday, April 26, 2010

Config transformations outside of web app builds

If you are using Visual Studio 2010 then you may already be familiar with the Web.config transformations that are now available. What you might not know is that you can use that same technology to transform config files outside of the build process. You will need Visual Studio 2010 installed on the machine where you perform these transformations. It is very easy to perform these transformation as well. Let’s say that we start with the app.config file shown below.

<configuration>
    <connectionStrings>
        <clear/>
        <add name="Default" connectionString="Data Source=localhost;Initial Catalog=Sample01;Integrated Security=True;" />
    </connectionStrings>
    
    <appSettings>
        <add key="contactEmail" value="contact@demo.example.com"/>
        <add key="siteUrl" value="http://demo.example.com"/>
    </appSettings>
    
</configuration>

Then we create another file, transform.xml, which contains our transformations. That file is shown below.

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
    <connectionStrings>
        <clear/>
        <add name="Default" connectionString="Data Source=NOT-localhost;Initial Catalog=Sample01;Integrated Security=True;" 
             xdt:Locator="Match(name)" xdt:Transform="Replace"/>
    </connectionStrings>

    <appSettings>
        <add key="contactEmail" value="contact@example.com" xdt:Locator="Match(key)" xdt:Transform="Replace"/>
        <add key="siteUrl" value="http://example.com" xdt:Locator="Match(key)" xdt:Transform="Replace"/>
    </appSettings>

</configuration>

Then we can easily execute the transformations by using MSBuild. So I created a file named trans.proj and it is shown below.

<Project ToolsVersion="4.0" DefaultTargets="Demo" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <UsingTask TaskName="TransformXml"
             AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll"/>

    <Target Name="Demo">
        <TransformXml Source="app.config"
                      Transform="Transform.xml"
                      Destination="app.prod.config"/>
    </Target>
</Project>

This MSBuild file uses the TransformXml task which is shipped with Visual Studio 2010. We specify the source file, transform file and the destination. Pretty straight forward.

In order to execute this I open a Visual Studio 2010 command prompt, browse to the directory containing both files, and enter the following command

msbuild trans.proj /t:Demo

Once you do this then you will find the file app.prod.config with the following contents.

<configuration>
    <connectionStrings>
        <clear/>
        <add name="Default" connectionString="Data Source=NOT-localhost;Initial Catalog=Sample01;Integrated Security=True;"/>
    </connectionStrings>
    
    <appSettings>
        <add key="contactEmail" value="contact@example.com"/>
        <add key="siteUrl" value="http://example.com"/>
    </appSettings>
    
</configuration>

Sayed Ibrahim Hashimi

Config-Transformation | msbuild | MSBuild 4.0 | MSDeploy | Visual Studio | Visual Studio 2010 Monday, April 26, 2010 5:22:06 AM (GMT Daylight Time, UTC+01:00)  #     | 
Thursday, March 11, 2010

Web Deployment Tool (MSDeploy) Custom Provider Take 1

Disclaimer: Take what you read here with a grain of salt, I’m not an expert at providers … yet :)

I’ve known for quite a while that the Web Deployment Tool supports custom providers but I’ve never really looked at what it took to get actually write one. Tonight I wanted to write a simple provider to just sync a file from one place to another, just to see what is involved in creating that provider. In this post I describe how I created the provider. First you have to have the Web Deployment Tool installed, I’ve got the RTM version installed, but recently they delivered version 1.1 either should work. First things first, you need to create a class library project in Visual Studio. For this example I used Visual Studio 2010 RC for the reason that it’s the only version of Visual Studio that I have installed on this machine. If you are using Visual Studio 2010 make sure that you specify to build for .NET 3.5 because MSDeploy won’t pickup any providers written in .NET 4.0. To specify that your project should build for .NET 3.5 go to Project->Properties then on the Application tab pick the Target Framework to be .NET 3.5. See the image below for clarification.

targetframework-.net35

You will need to reference the two assemblies Microsoft.Web.Deployment.dll and Microsoft.Web.Delegation.dll. You can find both in the %Program Files%\IIS\Microsoft Web Deploy folder.

After this you need to create the class which is the provider. I called my CustomFileProvider because it will only sync a single file. The class should extend the DeploymentObjectProvider class. There are a couple abstract items that you must implement those are.

CreateKeyAttributeData

From what I can see this method is used to indicate how the “key attribute” is used. For instance when you use a contentPath provider you would use a statement like msdeploy –verb:sync –source:contentPath=C:\one\pathToSync –dest:… So we can see that the value C:\one\pathToSync is passed to the provider without a name. This is the key attribute value. This method for my provider looks like the following.

public override DeploymentObjectAttributeData CreateKeyAttributeData()
{
    DeploymentObjectAttributeData attributeData = new DeploymentObjectAttributeData(
        CustomFileProvider.KeyAttributeName,
        this.FilePath,
        DeploymentObjectAttributeKind.CaseInsensitiveCompare);

    return attributeData;
}

In this case CustomFileProvider.KeyAttributeName is a const whose value is path and its value is provided from the FilePath property. The other item that you have to override is the Name property.

Name

This property returns the name of the provider. In all the samples that I have seen (which is not very much) this name always agrees with the name of the custom provider factory, more on that in a bit. So in their example I had mine return the value customFile which my factory also returns.

Outside of these two items there are some other methods that you need to know about those are covered below.

GetAttributes

The GetAttributes method is kinda interesting. This method will be called on both the source and destination and you need to understand which context its being called in and act accordingly. You can determine if you are executing on the source or dest by using the BaseContext.IsDestinationObject property. So for this provider if you are in the source you want to ensure that the file specified exists, if not then raise a DeploymentFatalExcepton, this will stop the sync. If you are on the destination you could perform some checks to see if the file is up-to-date or not. For a simple provider you can force a sync to occur. You would do this by raising a DeploymentException. When you raise this exception at this time it causes the Add method to be called, which is exactly what we want. Here is my version of the GetAttributes method.

public override void GetAttributes(DeploymentAddAttributeContext addContext)
{
    if (this.BaseContext.IsDestinationObject)
    {
        // if we are on the destination and the file doesn't exist then we need to throw an exception
        // to ensure that the file gets synced. This happens because the Add command will be called for us.

        // Since I'm throwing an exception here Add will always be called, we could check to see if this file
        // was up-to-date and if so then skip this exception.
        throw new DeploymentException();
    }
    else
    {
        // We are acting on the source object here, make sure that the file exists on disk
        if (!File.Exists(this.FilePath))
        {
            string message = string.Format("File <{0}> does not exist",this.FilePath);
            throw new DeploymentFatalException(message);
        }
    }

    base.GetAttributes(addContext);
}

For the most part the only thing left for this simple provider to implement is to override the Add method. First I will show the method then discuss its content. Here is the method.

public override void Add(DeploymentObject source, bool whatIf)
{
    // This is called on the Destination so this.FilePath is the dest path not source path
    if (!whatIf && File.Exists(source.ProviderContext.Path))
    {
        // We can let MSDeploy do the actual sync for us using existig provider
        DeploymentProviderOptions sourceProviderOptions = new DeploymentProviderOptions(DeploymentWellKnownProvider.FilePath);
        sourceProviderOptions.Path = source.ProviderContext.Path;

        using (DeploymentObject sourceObject = DeploymentManager.CreateObject(sourceProviderOptions, new DeploymentBaseOptions()))
        {
            DeploymentProviderOptions destProviderOptions = new DeploymentProviderOptions(DeploymentWellKnownProvider.FilePath);
            destProviderOptions.Path = this.FilePath;

            // Make the call to perform an actual sync
            sourceObject.SyncTo(destProviderOptions, new DeploymentBaseOptions(), new DeploymentSyncOptions());
        }
    }
}

First I check to make sure that we are not doing a whatif run (i.e. a run where we don’t want to physically perform the action) and that the source file exists. Take note of the fact that I’m explicitly using source.ProviderContext.Path to get the source path. This provider has a property, FilePath, which contains the path but it could be either source path or dest path depending on which end you are executing in. the source.ProviderContent.Path will always point to the source value. After that you can see that I’m actually leveraging an existing provider the FilePath provider to do the actual sync for me. So all the dirty work is his job! If you are writing a provider make sure to re-use any existing providers that you can, because the code for this part looks like it can get nasty. I’ll leave that for another post.

After I prepare the source options I create an instance of the DeploymentObject class, prepare the FilePath provider and call SyncTo on the object., this is where the physical sync occurs. That is basically it for the provider itself now we need to create a provider factory class which is the guy who knows how to create our providers for us.

Fortunately creating custom provider factories is even easier then creating custom providers themselves. I called mine CustomFileProviderFactory and the entire class is shown below.

[DeploymentProviderFactory]
public class CustomFileProviderFactory : DeploymentProviderFactory
{
    protected override DeploymentObjectProvider Create(DeploymentProviderContext providerContext, DeploymentBaseContext baseContext)
    {
        return new CustomFileProvider(providerContext, baseContext);
    }

    public override string Description
    {
        get { return @"Custom provider to copy a file"; }
    }

    public override string ExamplePath
    {
        get { return @"c:\somefile.txt"; }
    }

    public override string FriendlyName
    {
        get { return "customFile"; }
    }
    public override string Name
    {
        get { return "customFile"; }
    }
}

A few things to make note of; your class should extend the DeploymentProviderFactory class and it should have the DeploymentProviderFactory attribute attached to it. Besides that there are two properties FriendlyName and Name, once again in all the samples I have seen they are always the same and always equal to the Name property on the provider itself. I followed suit and copied them. I’m still trying to figure out more about what each of these actually do, but for now I’m OK with leaving them to be the same. So that is basically it.

In order to have MSDeploy use the provider you have to create a folder named Extensibility under the %Program Files%\IIS\Microsoft Web Deploy folder if it doesn’t exist, and then copy the assembly into that folder. And then you are good to go. Here is the snippet showing my custom provider in action!

C:\temp\MSDeploy>msdeploy -verb:sync -source:customFile=C:\temp\MSDeploy\Source\source.txt -dest:customFile=C:\temp
\MSDeploy\Dest\one.txt -verbose
Verbose: Performing synchronization pass #1.
Info: Adding MSDeploy.customFile (MSDeploy.customFile).
Info: Adding customFile (C:\temp\MSDeploy\Dest\one.txt).
Verbose: The dependency check 'DependencyCheckInUse' found no issues.
Verbose: The synchronization completed in 1 pass(es).
Total changes: 2 (2 added, 0 deleted, 0 updated, 0 parameters changed, 0 bytes copied)

This was a pretty basic provider, but you have to start somewhere. I will post more about custom providers as I find out more.

You can download the entire source at http://sedotech.com/Resources#CustomProviders under the Custom Providers heading of the MSDeploy section.

Sayed Ibrahim Hashimi

Custom Provider | MSDeploy | Web Deployment Tool Thursday, March 11, 2010 6:04:47 AM (GMT Standard Time, UTC+00:00)  #     | 
Wednesday, March 10, 2010

Web Deployment Tool: Including other Files

I just received a message from a reader asking about how he can extend the package process in Visual Studio 2010 RC to include files that his web project doesn't contain or reference. If you are not familiar with this Visual Studio 2010 has support for creating Web Packages now. These packages can be used with the Web Deployment Tool to simply deployments. The Web Deployment Tool is also known as MSDeploy.

He was actually asking about including external dependencies, but in this post I will show how to include some text files which are already written to disk. To extend this to use those dependencies should be pretty easy. Here is what I did:

  1. Created a new ASP.NET MVC 2 Project (because he stated this is what he has)
  2. Added a folder named Extra Files one folder above where the .csproj file is located and put a few files there
  3. In Visual Studio right clicked on the project selected “Unload Project”
  4. In Visual Studio right clicked on the project selected “Edit project”

Then at the bottom of the project file (right above the </Project> statement). I inserted the following XML fragments.

<PropertyGroup>
  <CopyAllFilesToSingleFolderForPackageDependsOn>
    CustomCollectFiles;
    $(CopyAllFilesToSingleFolderForPackageDependsOn);
  </CopyAllFilesToSingleFolderForPackageDependsOn>
</PropertyGroup>
<Target Name="CustomCollectFiles">
  <ItemGroup>
    <_CustomFiles Include="..\Extra Files\**\*">
      <DestinationRelativePath>%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
    </_CustomFiles>

    <FilesForPackagingFromProject  Include="%(_CustomFiles.Identity)">
      <DestinationRelativePath>Extra Files\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
    </FilesForPackagingFromProject>
  </ItemGroup>
</Target>

Here I do a few things. First I extend the CopyAllFilesToSingleFolderForPackage target by extending its DependsOn property to include my target CustomCollectFiles. This will inject my target at the right time into the Web Publishing Pipeline. Inside that target I need to add my files into the FilesForPackagingFromProject item group, but I must do so in a particular manner. Specifically I have to define the relative path to where it should be written. This captured inside the DestinationRelativePath metadata item. This is required because sometimes you may have a file which is named, or in a different folder, than it was originally. After you do that you will see that the web package that is created when you create a web package from Visual Studio (or from the command line using msbuild.exe for that matter) contains your custom files.

I just posted a blog about my upcoming talk discussing Web Deployments and ASP.NET MVC, once again check it out :)

Sayed Ibrahim Hashimi

Deployment | MSDeploy | Web Deployment Tool Wednesday, March 10, 2010 5:26:14 AM (GMT Standard Time, UTC+00:00)  #     | 

Speaking on Automating Web Deployments and ASP.NET MVC

I will be speaking at the Orlando Code Camp on Saturday March 27. I will be giving two session; one on Simplifying deployments with MSDeploy and Visual Studio 2010 and the other on ASP.NET MVC View Helpers. By the way, the other name for MSDeploy is the Web Deployment Tool.

If you have ever had issues with deploying web applications (which includes everyone who has ever deployed a web app :) ) then you need to attend my session. I will discuss the three major scenarios of deploying web applications:

I will be demonstrating how to perform 2 of the 3; deploying to local IIS server and to a 3rd party host. Since I won’t have any other machines besides my notebook I will not be demoing how to deploy to an IIS server on the intranet, but it is very similar to the other 2 scenarios. There has been a lot of work in the area of web deployment (deployment in general actually) recently which could really help spare you of a lot of headache. I presented this at the South Florida Code Camp a couple weeks ago and a person actually stated in the session “There are a lot of people who wish they were in here right now”! If you are in the area then you should attend my session, you won’t regret it.

Here is the abstract:

Visual Studio 2010 will be shipped including integration with Microsoft’s Web Deployment Tool, MSDeploy. For quite a while web deployments have been very difficult to manage and automate. With MSDeploy you can manage the complexities of web deployments. One of the great aspects of the Web Deployment Tool is that it is integrated into Visual Studio with MSBuild tasks and targets. Since Team Foundation Build can leverage MSBuild we can take advantage of those tasks and targets to automate web deployments using Team Build.

My other talk will be on creating leaner views with ASP.NET MVC View Helpers. If you are using ASP.NET MVC then this is one of the sessions you’ll be interested in. I will be getting in depth about ASP.NET View Helpers, and just talking ASP.NET MVC in general. I gave this talk at the Jacksonville Developers User Group last week and it was great. I’m very excited about these two talks, I’m sure they will be great. Here is the abstract.

If you have been using ASP.NETMVC then you certainly have been using some of the built in view helper methods that are available, you know those expressions like Html.TextBox("textBoxName") and Html.ValidationMessage("Required"). View helpers are nothing more than extension methods which create HTML that is injected into your views based on the method and its parameters. Creating your own view helpers is very simple and can be extremely beneficial. By writing your own custom view helpers you will benefit in at least the following ways

I have published a 22 page paper discussing custom ASP.NET MVC view helpers along with a sample app at http://mvcviewhelpers.codeplex.com/ if you are interested.

 

If you are in the area this weekend its going to be a great event. I think there were >400 people there last year, so it should be a good turn out this year as well. I hope to see you there.

Sayed Ibrahim Hashimi

MSDeploy | speaking | Visual Studio 2010 | Web Deployment Tool Wednesday, March 10, 2010 3:29:22 AM (GMT Standard Time, UTC+00:00)  #     | 
Monday, December 07, 2009

MSDeploy Syncing 2 or More Folders

A while back someone asked me if you could sync 2 or more folders with one statement using MSDeploy. I said of course, if you perform the sync using manifest files. Manifest files allow you to "group" sync operations into a file. When you invoke msdeploy.exe and point it to a manifest file, each provider will be executed in the order in which it appears inside the manifest file. A common scenario for using manifest files is to sync websites. This way you can specify the files that should be synced, the website (application) name, ACL values, etc. But you are not limited to using manifest files for web related sync operations. When using manifest files, you would specify the provider to be manifest. We will see this in the command used to snyc two folders. Often times when using a manifest file for the source you will also use one for the destination. Here are the two files.

SourceManifest.xml

<sitemanifest>

  <contentPath path="C:\temp\MSDeploy\Source01"/>

  <contentPath path="C:\temp\MSDeploy\Source02" />

</sitemanifest>

DestManifest.xml

<sitemanifest>

  <contentPath path="E:\temp\MSDeploy\Source01" />

  <contentPath path="E:\temp\MSDeploy\Source02" />

</sitemanifest>

In this example I am syncing two folders C:\temp\MSDeploy\Source01 and C:\temp\MSDeploy\Source02 to another drive location on E. The command to perform the sync would be

msdeploy -verb:sync -source:manifest=sourceManifest.xml -dest:manifest=destManifest.xml

And here are the results of that sync operation, when the destination directories don't exist.

C:\temp\MSDeploy>msdeploy -verb:sync -source:manifest=sourceManifest.xml -dest:manifest=destManifest.xml

Info: Adding sitemanifest (sitemanifest).

Info: Adding contentPath (E:\temp\MSDeploy\Source01).

Info: Adding dirPath (E:\temp\MSDeploy\Source01).

Info: Adding child filePath (E:\temp\MSDeploy\Source01\01.txt).

Info: Adding child filePath (E:\temp\MSDeploy\Source01\02.txt).

Info: Adding child filePath (E:\temp\MSDeploy\Source01\03.txt).

Info: Adding child filePath (E:\temp\MSDeploy\Source01\04.txt).

Info: Adding contentPath (E:\temp\MSDeploy\Source02).

Info: Adding dirPath (E:\temp\MSDeploy\Source02).

Info: Adding child filePath (E:\temp\MSDeploy\Source02\01.txt).

Info: Adding child filePath (E:\temp\MSDeploy\Source02\02.txt).

Info: Adding child filePath (E:\temp\MSDeploy\Source02\03.txt).

Info: Adding child filePath (E:\temp\MSDeploy\Source02\04.txt).

Total changes: 13 (13 added, 0 deleted, 0 updated, 0 parameters changed, 0 bytes copied)

As you can see the destination directories were created and the files synced into the destination folders. First all the content of the Source01 folder is synced and then the Source02 folder as expected. If you perform the sync operation and all files are up-to-date then no changes will be made.

This is just a very basic example of how you can use MSDeploy manifest files to perform a sync operation, but you can create manifest files that perform many different actions. Visual Studio 2010 uses manifest files when it creates the web packages for deployment.

 

Sayed Ibrahim Hashimi

MSDeploy Monday, December 07, 2009 4:50:37 AM (GMT Standard Time, UTC+00:00)  #     | 
Tuesday, October 27, 2009

MSDeploy Presentation Materials

Last week I presented MSDeploy in a LiveMeeting session. I'm glad to say that the presentation is now available at https://www.livemeeting.com/cc/mvp/view?id=PR7D6Z. If you are interested in getting a quick look at MSDeploy then this is a good place to start. I demonstrate how we can use MSDeploy / VS2010 in the following scenarios.

To my knowledge this is the first online presentation of the RTW version of MSDeploy.

You can download the slide deck at http://sedodream.com/content/binary/MSDeploy_Sayed-Ibrahim-Hashimi-2009-10.pdf

 

For reference here are the links from the resources slide

 

I would like to thank Charles Sterling, Vishal Joshi, and Mei Liang for making this happen.

Sayed Ibrahim Hashimi

MSDeploy | Presentations Tuesday, October 27, 2009 3:21:20 AM (GMT Standard Time, UTC+00:00)  #     | 
Friday, October 09, 2009

MSDeploy: Interactive Online Session

I will be giving an online LiveMeeting Session hosted by Microsoft next week on Wednesday October 14, 2009 at 4 PDT (Redmond Time). The title is Simplifying Deployment with the Web Deployment Tool (MSDeploy). If you are not aware of MSDeploy it is a newly released tool to ease the pain of deploying ASP.NET sites. If you are doing any type of deployment of ASP.NET sites (Manual or Automated) then you must check out MSDeploy, it will change how you look at deployment of ASP.NET sites all together. Right now there is not an abundant amount of knowledge or material available on this tool, but I think that will change soon. Hopefully I can contribute to some of that. In any case, if you are available I would love to have you check out my session. There will be some guys from Microsoft on the line including the Program Manager of the Web Deployment Tool Vishal Joshi. I'm sure he will chime in when I try to mislead you guys by feeding your mis-information.

Here is the info about the presentation.

Simplifying Deployment with the Web Deployment Tool (MSDeploy)

You are invited to join the talk which is scheduled for

Wednesday, October 14th, 2009 | 4:00pm – 5:00pm (PDT, Redmond time)

Abstract

Deploying ASP.NET Websites has always been a challenge and different teams have used different approaches to overcoming those challenges. Microsoft has offered some support for making deployment easier in the past. For instance they first introduced Web Deployment Projects for Visual Studio 2005, and also have a version for 2008. Web Deployment Projects do greatly simplify the process of calling the aspnet_compiler and aspnet_merge tool but even though their title states "Deployment" they had no support for physically deploying the site. Now Microsoft has introduced the Web Deployment Tool, also known as MSDeploy. MSDeploy will bridge the gap between taking a web site and physically deploying it to its destination. With MSDeploy you can easily and very effectively perform tasks such as pushing an ASP.NET site (Web site, Web Application Project, ASP.NET, etc) from one machine to several other machines. This is achieved by the target machines having the MSDeploy Remote Agent Service installed and running. You can sync two different Web Sites that are hosted in IIS, you can create a web package (simply a .zip file) and use that as your source, you can sync two different folders, and many other options. Another compelling feature of MSDeploy is that it will be integrated into Visual Studio 2010. From Visual Studio 2010 you can compile your ASP.NET Web Application Project and then create the Web Package which contains all your content files plus IIS settings. This one file will full describe your web.

Live Meeting Information

Join the meeting.
Audio Information
Computer Audio
To use computer audio, you need speakers and microphone, or a headset.
Telephone conferencing
Use the information below to connect:
Toll-free: +1 (866) 500-6738
Toll: +1 (203) 480-8000
Participant code: 5460396

Please join 10 minutes prior to the start time.

First Time Users:
To save time before the meeting,
check your system to make sure it is ready to use Microsoft Office Live Meeting.
Notes

Troubleshooting
Unable to join the meeting? Follow these steps:

1. Copy this address and paste it into your web browser:
https://www.livemeeting.com/cc/mvp/join

2. Copy and paste the required information:
Meeting ID: PR7D6Z
Entry Code: A5128ML0Y0D
Location:
https://www.livemeeting.com/cc/mvp

If you still cannot enter the meeting, contact support

Note

Microsoft Office Live Meeting can be used to record meetings. By participating in this meeting, you agree that your communications may be monitored or recorded at any time during the meeting.

 

Sayed Ibrahim Hashimi

 

 

Deployment | LiveMeeting | MSDeploy | Video Friday, October 09, 2009 3:43:27 AM (GMT Daylight Time, UTC+01:00)  #     |