Basics on Using the Web Deploy API

I’ve seen a lot of posts on how to use Web Deploy through various tools and clients, but wasn’t able to find a good resource on doing these things through our API.  So I decided that I would try to help alleviate some of the confusion here. To begin using the Web Deploy API, it helps to understand a little bit about terminology, components, and its general workflow before diving in:

  • Provider – Web Deploy uses a provider model, where each provider is responsible for syncing specific types of data.  When performing a sync, you can specify built-in providers, or 3rd party providers if they’re installed.  (writing a custom provider is not covered by this post)
  • Parameters – Used for changing the values of an object while it is being synchronized. (see parameterization)
  • Rule Handlers – Run on the destination while a sync operation is in progress to affect the result of an operation based on different criteria.  Some rules are on by default, while others need to be manually enabled.  Rules may either be built-in, or installed by a 3rd party.  (writing a custom rule is not covered by this post)
  • Web Deployment Agent Service (aka msdepsvc) – A service that Web Deploy installs which allows us to perform remote publishing/synchronization.  The “Agent” is typically used in administrator-only scenario’s (where you have full privileges on the remote machine) with NTLM authentication.
  • Web Management Service (aka wmsvc) – An optional service that gets installed with IIS for remote server management of IIS machines.
  • Web Deployment Handler – A handler which hooks into the Web Management Service to handle publishing to IIS.  The handler is run in a low-privileged environment which is why it is usually used by hosters to allow their users to publish to IIS.

 

Basic Workflow

When Web Deploy begins a sync, it first compares its source object to its destination object.  The way it performs the comparison is based off of the implementation of whichever provider is being used.  If there are child providers of the current provider, Web Deploy will also compare all of its children to see if they exist, need to be updated, or need to be deleted on the destination.  For every CRUD operation that a provider performs on the destination, there are also rule handlers that get checked to see if there is something special that needs to happen.  If so, then a rule can either block a sync entirely, skip a change that may occur, or modify the data being synchronized somehow.  If Web Deploy is synchronizing to a remote endpoint via the msdepsvc or wmsvc, then it will make an HTTP connection to that endpoint in order to synchronize its data.  Web Deploy will only send over data that is necessary to complete a sync in order to minimize the amount of network traffic that goes over the wire.

 

Command Line Basics 

To begin using the Web Deploy API, I find it’s often easiest to reference the usage of the msdeploy.exe tool since it is probably the lowest level wrapper you could use with the highest amount of functionality. If you have installed Web Deploy, then you should have a copy of it under "%programfiles%\IIS\Microsoft Web Deploy V3”.  A typical command has the following structure:

msdeploy.exe -verb:<verb> -source:<providerName>=<sourcePath>,<providerOptions> -dest:<providerName>=<destPath>,<providerOptions>

  • Verb – The most common verbs are “sync” and “dump”.
  • ProviderName – The name of a built-in or custom provider.
  • ProviderOptions – Settings for whatever provider you’re using.

Command line help gets more specific based on the options that you enter.  For instance, if I want a list of all providers, rule handlers, and other options, I could simply run:

msdeploy.exe -?

But if I wanted specific help on a specific provider’s options, I could run:

msdeploy.exe -verb:<verb> -source:<providerName> –?

More advanced commands which includes publishing to a remote endpoint with rules and parameters may look something like this:

msdeploy.exe -verb:<verb> -source:<providerName>=<sourcePath>,<providerOptions> -dest:<providerName>=<destPath>,<providerOptions>,computername=<remoteComputerName> -enablerule:<ruleName> -declareParam:name=ParamName,type=ProviderPath,scope=<providerName>,match=<sourcePath>

As you can see, the command line can easily get pretty hairy.  But having a basic understanding of it will help you to understand how the API works and help you to understand what’s possible without writing any code.  For a complete command line reference, see our Technet documentation

 

Synchronizing Two directories With Tracing

Let’s start simple.  To sync one directory to another on the same machine, I could run the following command:

msdeploy -verb:sync -source:dirpath=c:\source -dest:dirpath=c:\dest

This will perform a ONE-WAY sync from source to destination.  Web Deploy always performs a diff before making any changes, so if no changes are necessary, it will not make them.  To achieve this through the API, you can use the following code.

   1: public static void SyncDirsExample()
   2: {
   3:     DeploymentSyncOptions syncOptions = new DeploymentSyncOptions();
   4:     DeploymentBaseOptions sourceBaseOptions = new DeploymentBaseOptions();
   5:     sourceBaseOptions.Trace += TraceEventHandler;
   6:     sourceBaseOptions.TraceLevel = TraceLevel.Verbose;
   7:  
   8:     DeploymentBaseOptions destBaseOptions = new DeploymentBaseOptions();
   9:     destBaseOptions.Trace += TraceEventHandler;
  10:     destBaseOptions.TraceLevel = TraceLevel.Verbose;
  11:  
  12:     DeploymentProviderOptions destProviderOptions =
  13:         new DeploymentProviderOptions(DeploymentWellKnownProvider.DirPath);
  14:  
  15:     using (DeploymentObject sourceObj =
  16:         DeploymentManager.CreateObject(
  17:             DeploymentWellKnownProvider.DirPath, @"c:\source", sourceBaseOptions))
  18:     {
  19:         destProviderOptions.Path = @"c:\dest";
  20:         sourceObj.SyncTo(destProviderOptions, destBaseOptions, syncOptions);
  21:     }
  22: }
  23:  
  24: static void TraceEventHandler(object sender, DeploymentTraceEventArgs e)
  25: {
  26:     Console.WriteLine(e.Message);
  27: }
  28:  

 

Whenever you’re syncing from a source to a destination, you need to first create a source object based on the provider you’re using.  When you create the source object, Web Deploy will use the information you gave it to verify that the object is valid and can be read.  If this succeeds, then you use that object to “SyncTo” your destination.  In most cases your destination provider will match your source provider, but in some cases this may not be true (e.g. when you’re syncing to/from a zip package). 

Here’s some info on some of the objects we’re using:

  • DeploymentSyncOptions –Used to specify settings that are not specific to either the source or destination.  (e.g. Rules, Parameters, Whatif, etc…)
  • DeploymentBaseOptions – Used to specify settings that are specific to an endpoint.  (e.g. computer name, remote endpoint, credentials, etc…).  We also used this object to setup tracing from different endpoints.
  • DeploymentProviderOptions – Used to specify settings that are specific to a provider.
  • DeploymentObject – Represents an object to be sync’d based on the provider specified in creating that object.

 

Synchronizing a directory to a remote machine

There are two remote endpoints that Web Deploy can connect to.  The Web Deployment Agent Service (msdepsvc) and the Web Management Service (wmsvc).  The simple difference between the two is that the msdepsvc requires administrative privileges and is primarily used by server administrators for IIS migrations.  While the WMSVC service is typically used by developers to push their web site content to a hoster like GoDaddy, Azure Web Sites, etc...  Here is how you would do this on the command line. 

Sync to Msdepsvc using Command line

msdeploy -verb:sync -source:dirpath=c:\source -dest:dirpath=c:\dest,computername="remoteComputerName"

Sync to WMSVC using Command Line

msdeploy -verb:sync -source:contentpath=c:\source -dest:contentpath=mySite/dest,computername=https://remoteComputerName:8172/msdeploy.axd?site=mySite,username=myUserName,password=myPassword,authtype=basic -allowuntrusted

You may be wondering why does the wmsvc command look so much longer, and why am I using different providers between the two endpoints?  Well, here’s a few reasons:

1. You can actually specify a shorter wmsvc command with the wmsvc provider setting.  But since we need the full URL to utilize the API, I spelled the whole thing out here. 

2. Since we need to use “Basic” authentication with wmsvc, you also need to spell out your credentials since they cannot be implied from your user context like with NTLM (which is the default if not specified).

3. The reason why I used a different provider with wmsvc is because by default, the Web Deployment Handler (which runs within wmsvc) blocks the dirPath provider from being used for security reasons.  The contentPath provider is a wrapper of the dirPath provider that has knowledge about IIS sites/apps and is more secure to utilize in a hosted environment.  It works similar to a dirPath provider except instead of specifying a root drive, you can specify a root site/app location.

4. The “-allowuntrusted” flag tells Web Deploy to ignore certificate validation which will normally happen in non-production environments.

Now that we have a basic understanding of the different endpoints, let’s spell it out through the API:

Sync to Msdepsvc using API

   1: DeploymentSyncOptions syncOptions = new DeploymentSyncOptions();
   2: DeploymentBaseOptions sourceBaseOptions = new DeploymentBaseOptions();
   3: DeploymentBaseOptions destBaseOptions = new DeploymentBaseOptions();
   4: destBaseOptions.ComputerName = "remoteComputerName";
   5:  
   6: DeploymentProviderOptions destProviderOptions =
   7:     new DeploymentProviderOptions(DeploymentWellKnownProvider.DirPath);
   8:  
   9: using (DeploymentObject sourceObj =
  10:     DeploymentManager.CreateObject(
  11:         DeploymentWellKnownProvider.DirPath, @"c:\source", sourceBaseOptions))
  12: {
  13:     destProviderOptions.Path = @"c:\dest";
  14:     sourceObj.SyncTo(destProviderOptions, destBaseOptions, syncOptions);
  15: }

 

Sync to WMSVC using API

   1: // Equivalent of the "-allowuntrusted" flag to ignore certificate validation on server.  In a production system you shouldn't need this.
   2: System.Net.ServicePointManager.ServerCertificateValidationCallback
   3:     += new System.Net.Security.RemoteCertificateValidationCallback(
   4:     (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) =>
   5:     { return true; });
   6:  
   7: DeploymentSyncOptions syncOptions = new DeploymentSyncOptions();
   8: DeploymentBaseOptions sourceBaseOptions = new DeploymentBaseOptions();
   9: DeploymentBaseOptions destBaseOptions = new DeploymentBaseOptions();
  10:  
  11: destBaseOptions.ComputerName = "https://remoteComputerName:8172/msdeploy.axd?site=mySite";
  12: destBaseOptions.UserName = "myUserName";
  13: destBaseOptions.Password = "myPassword";
  14: destBaseOptions.AuthenticationType = "basic";
  15:  
  16: DeploymentProviderOptions destProviderOptions =
  17:     new DeploymentProviderOptions(DeploymentWellKnownProvider.ContentPath);
  18:  
  19: using (DeploymentObject sourceObj =
  20:     DeploymentManager.CreateObject(
  21:         DeploymentWellKnownProvider.ContentPath, @"c:\source", sourceBaseOptions))
  22: {
  23:     destProviderOptions.Path = @"mysite/dest";
  24:     sourceObj.SyncTo(destProviderOptions, destBaseOptions, syncOptions);
  25: }

 

Disabling/Enabling Rules

To enable or disable a rule on the command line, you only need to specify the “-enablerule” or “-disablerule” switches.  The following command will sync 2 directories, but will not delete any content in the destination directory.

msdeploy -verb:sync -source:dirpath=c:\source -dest:dirpath=c:\dest –enablerule:donotdeleterule

To do this from code, you need to find the DoNotDeleteRule, and then add it to the rules collection:

   1: DeploymentSyncOptions syncOptions = new DeploymentSyncOptions();
   2: DeploymentRule rule = null;
   3: DeploymentRuleCollection rules = DeploymentSyncOptions.GetAvailableRules();
   4:  
   5: rules.TryGetValue("DoNotDeleteRule", out rule);
   6: syncOptions.Rules.Add(rule);
   7:  
   8: DeploymentBaseOptions sourceBaseOptions = new DeploymentBaseOptions();
   9: DeploymentBaseOptions destBaseOptions = new DeploymentBaseOptions();
  10: DeploymentProviderOptions destProviderOptions =
  11:     new DeploymentProviderOptions(DeploymentWellKnownProvider.DirPath);
  12:  
  13: using (DeploymentObject sourceObj =
  14:     DeploymentManager.CreateObject(
  15:         DeploymentWellKnownProvider.DirPath, @"c:\source", sourceBaseOptions))
  16: {
  17:     destProviderOptions.Path = @"c:\dest";
  18:     sourceObj.SyncTo(destProviderOptions, destBaseOptions, syncOptions);
  19: }

Likewise, if you want to disable a rule, you just need to remove it from the rules collection.

 

Multiple Provider Syncs 

The manifest provider allows you to specify multiple providers in a single sync operation.  For remote syncs, this is more efficient than running multiple individual sync operations because it means that Web Deploy can do all of its work without having to open new HTTP connections for every operation (in reality Web Deploy is still making multiple HTTP connections but this way that number of connections is minimized).  The manifest provider takes in a simple XML file that has a list of providers that you would like to use.

SourceManifest.xml:

<?xml version="1.0" encoding="utf-8" ?>
<m>
  <contentPath path="sourceApp" />
  <recycleApp path="sourceApp" />
</m>

DestManifest.xml

<?xml version="1.0" encoding="utf-8" ?>
<m>
  <contentPath path="destApp" />
  <recycleApp path="destApp" />
</m>

Using these two manifests, I can sync multiple providers in one session like so:

msdeploy.exe –verb:sync –source:manifest=SourceManifest.xml –dest:DestManifest.xml

Since I’m doing a local sync, I obviously had to use different source/destination paths for the providers within my manifest because otherwise I would sync objects to themselves.  However, if I’m doing a remote sync and wanted to simply use the same paths within my source manifest, I could use the “Auto” provider like so:

msdeploy.exe –verb:sync –source:manifest=SourceManifest.xml –dest:auto,computername=remoteComputername

The “Auto” provider is a really helpful provider because often, your source and destination paths are exactly the same.  I’m not going to show a code sample for this because it’s pretty much the same as the previous examples, except you just need to change the provider name and paths.  I just wanted to make sure you understood the concept of manifests.

 

Package Syncs

The package provider allows you create a zip file “package” of content/settings that can be applied later either as a backup/restore, or if you just need to manually apply it somewhere else.  Borrowing from the earlier manifest example, you can create a package like so:

msdeploy.exe –verb:sync –source:manifest=SourceManifest.xml –dest:package=c:\myPackage.zip

Now if I would like to apply the package at another time, I could do it like so:

msdeploy.exe –verb:sync –source:manifest=c:\myPackage.zip –dest:auto

or

msdeploy.exe –verb:sync –source:manifest=c:\myPackage.zip –dest:manifest=DestManifest.xml

Again, we don’t need code samples for this because it’s the same as the previous examples, just change the provider type and paths.

 

Changing Provider Paths at Runtime Using Parameterization

Sometimes it makes sense to have the ability to change the path of the destination provider at run-time.  For instance, if you create a source manifest or package that you would like to sync to multiple locations that have different destination paths.  One way to do this would be to create a new manifest for every destination that you’re syncing to that has every path specified for every destination.  Or you could use a feature called parameterization to change some provider paths at run-time.  Here’s an example of changing only the contentPath provider path from the manifest we saw earlier:

msdeploy.exe -verb:sync –source:manifest=sourceManifest.xml -dest:auto -setparam:kind=providerPath,scope=contentPath,match=.*,value=destApp

Uh… What?  Parameterization is a powerful feature, but it can often be complicated to craft.  Explaining it in full detail is out of scope for this article, but you can get more details here.  For now, just accept my quick explanation of the arguments for this example:

  • setParam – Creates a single parameter.  You can specify multiple “-setParam” arguments. 
  • kind – The type of parameterization to use.  Other popular options include XMLFile or TextFile, which allow you to replace specific pieces of file content during deployment.  For a full list, visit links above.
  • scope – Since we chose “providerPath” parameterization, our scope narrows down our choice to a specific provider type.
  • match – Since we chose “providerPath” parameterization, our match is a regular expression against a specific provider path.
  • value – Since we chose “providerPath” parameterization, value is the what we’ll replace the matched provider path with on the destination.

With this knowledge, we know that in the example above, parameterization will therefore replace the contentPath provider path on the destination, but will not touch the recycleApp provider path.  Now let’s see how to do this in code:

   1: DeploymentSyncOptions syncOptions = new DeploymentSyncOptions();
   2: DeploymentBaseOptions sourceBaseOptions = new DeploymentBaseOptions();
   3: DeploymentBaseOptions destBaseOptions = new DeploymentBaseOptions();
   4: DeploymentProviderOptions destProviderOptions =
   5:     new DeploymentProviderOptions(DeploymentWellKnownProvider.Auto);
   6:  
   7: using (DeploymentObject sourceObj =
   8:     DeploymentManager.CreateObject(
   9:         DeploymentWellKnownProvider.Manifest, @"C:\SourceManifest.xml", sourceBaseOptions))
  10: {
  11:     DeploymentSyncParameter parameter = new DeploymentSyncParameter(
  12:         "TestParam",              // Name
  13:         "TestParam Description",  // Description
  14:         "destApp",                // Default Value to set
  15:         null);                    // Tag
  16:     
  17:     DeploymentSyncParameterEntry entry = new DeploymentSyncParameterEntry(
  18:         DeploymentSyncParameterEntryKind.ProviderPath,      // Kind
  19:         DeploymentWellKnownProvider.ContentPath.ToString(), // Scope
  20:         ".*",                                               // Match
  21:         null);                                              // Tag
  22:  
  23:     parameter.Add(entry);
  24:     sourceObj.SyncParameters.Add(parameter);
  25:  
  26:     sourceObj.SyncTo(destProviderOptions, destBaseOptions, syncOptions);
  27: }

As I mentioned earlier, there’s a lot more that you can do with parameterization, but for now, I think this covers the basics of how it works.

So I think I covered most of the basics for using the Web Deploy API.  Hopefully it was helpful for some people.  If there are other specific topics that people are interested in, let me know and I can cover them in another post.

No Comments