Writing Custom Rules for Web Deployment Tool

One of the users posted a question on the blog that he is trying to sync two servers which are being independently modified by users of the two servers. Thus he wants the two servers to be synced using MS Deploy but at the same time wants to exclude the files that are newer at the destination.

Adding this and such similar rules to customize the behavior of MS Deploy is easy and just requires a few simple steps. I am presenting a step by step guide for adding a Skip Update Newer File rule. This can be customized or modified easily to suite individuals needs. There is one such rule which comes bundled with the installation of MS Deploy by default. This is the DoNotDeleteRuleHandler which is disabled by default.

Download

You can download the project with the source code from here. [Disclaimer: This is not an official Microsoft download and hence not supported by Microsoft. Please direct all queries about it to me and I will respond as soon as possible]

Steps to Add a Custom Rule Handler:

  1. Write a managed assembly that overrides the update process of ms deploy as follows:
    1. A class that derives from DeploymentRuleHandler. For this you need to add a reference to Microsoft.Web.Deployment.dll in your install directory. This is just for compiling your assembly. At run time this assembly will be loaded from the GAC
    2. It should override the Update, Name, FriendlyName and Description functions of rulehandler. Below is a code snippet that does all this

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using Microsoft.Web.Deployment;

      namespace WDCustomRules
      {
          public class SkipNewerFilesUpdateRuleHandler : DeploymentRuleHandler
          {
              #region CONSTANTS
              private const string RULENAME = "SkipNewerFilesUpdateRule";
              private const string RULEFRIENDLYNAME = "Skip Newer Files on Update Rule";
              private const string RULEDESCRIPTION = "If the dest file has a later lastwritetime than a file from the source being copied, this rule will skip it";
              #endregion

              public override void Update(DeploymentSyncContext syncContext, DeploymentObject destinationObject, ref DeploymentObject sourceObject, ref bool proceed)
              {
                  if (sourceObject.Name == "filePath" && destinationObject.Name == "filePath")
                  {
                      DeploymentAttribute sourceLastWriteTimeAttribute;
                      DeploymentAttribute destLastWriteTimeAttribute;
                      if (sourceObject.Attributes.TryGetValue("lastWriteTime", out sourceLastWriteTimeAttribute) &&
                          destinationObject.Attributes.TryGetValue("lastWriteTime", out destLastWriteTimeAttribute))
                      {
                          DateTime sourceLastWriteTime = DateTime.Parse(sourceLastWriteTimeAttribute.Value); //, CultureInfo.InvariantCulture: for globalization later
                          DateTime destLastWriteTime = DateTime.Parse(destLastWriteTimeAttribute.Value);
                          if (sourceLastWriteTime < destLastWriteTime)
                          {
                              proceed = false;
                          }
                      }
                  }
              }

              public override string Name
              {
                  get { return RULENAME; }
              }

              public override string FriendlyName
              {
                  get { return RULEFRIENDLYNAME; }
              }

              public override string Description
              {
                  get { return RULEDESCRIPTION; }
              }
          }   
      }

  2. Build this assembly as WDCustomRules.SkipNewerFilesUpdateRuleHandler.dll and GAC it as gacutil –i WDCustomRules.SkipNewerFilesUpdateRuleHandler.dll. For help on how to create a signed assembly click here.
  3. Add the following information to the registry:
    1. Add a key SkipNewerFilesUpdateRule under HKLM\Software\Microsoft\IIS Extensions\MSDeploy\1\Rules. This name does not have to be same as the assembly name. Any name that you think suits the purpose.
    2. To this key add two String values:
      1. isdefault”. The value of this should be “true” or “false”. If this is true it will be applied to all verbs by default except dump. You can set it to false and enable the rule on the command line whenever you carry out a sync or migrate.
      2. type”. The value of this should be “CompleteAssemblyName, CompleteAssemblyName, Version=<version>, Culture=neutral, PublicKeyToken=<PublicKey>”. For example in this case it would be “WDCustomRules.SkipNewerFilesUpdateRuleHandler, WDCustomRules.SkipNewerFilesUpdateRuleHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8de34bc1deb35465”
        Since the name of the assembly is WDCustomRules.SkipNewerFilesUpdateRuleHandler.dll
  4. To verify that it does what I intend lets test it out. Create two folders test and test1 with the same content except that you have a file test.txt in test1 newer than the one in test folder. Lets run the command:       msdeploy -verb:sync -source:contentPath=C:\test -dest:contentPath=C:\test1 –verbose

Here’s the output:

Informational:  Performing synchronization pass #1
Informational:  Destination filePath (c:\test1\test.txt) does not match source (C:\test\test.txt) differing in attributes (size['1271','1414'],lastWritTime['01/01/2009 22:07:46','03/03/2009 19:24:42']). Update pending
Informational:  Update operation on filePath (C:\test\test.txt) skipped due to rule SkipNewerFilesUpdateRule
Informational:  Synchronization completed in 1 passes
Change count: 0

No Comments