Tuesday, September 2, 2008

Using NAnt custom task to wrap SDC Task to create VDir

I got my VDir code working, but there are some caveats that have to be watched, I've found.



   1:  using System;

   2:  using System.Text;

   3:  using NAnt.Core;

   4:  using NAnt.Core.Attributes;

   5:  using Microsoft.Sdc.Tasks;

   6:  using Microsoft.Build.Utilities;

   7:  using Microsoft.Build.Framework;

   8:  namespace Auswipe.NAntTasks.VDirTasks {

   9:    # region Delete VDir

  10:    [TaskName("deletevdir")]

  11:    public class DeleteVDir : NAnt.Core.Task {

  12:      private string vDirToDelete;

  13:      private string machineName;

  14:      private string webSiteName;

  15:      [TaskAttribute("vdirtodelete", Required = true)]

  16:      [StringValidator(AllowEmpty = false)]

  17:      public string VDirToDelete {

  18:        get { return vDirToDelete; }

  19:        set { vDirToDelete = value; }

  20:      }

  21:      [TaskAttribute("machinename", Required = true)]

  22:      [StringValidator(AllowEmpty = false)]

  23:      public string MachineName {

  24:        get { return machineName; }

  25:        set { machineName = value; }

  26:      }

  27:      [TaskAttribute("websitename", Required = true)]

  28:      [StringValidator(AllowEmpty = false)]

  29:      public string WebSiteName {

  30:        get { return webSiteName; }

  31:        set { webSiteName = value; }

  32:      }

  33:      protected override void ExecuteTask() {

  34:        Project.Log(Level.Info, "Auswipe.NAntTasks.VDirTasks : The following AppPool will be deleted: '" + vDirToDelete + "'");

  35:        try {

  36:          Microsoft.Sdc.Tasks.Web.WebSite.DeleteVirtualDirectory delVDirObject = new Microsoft.Sdc.Tasks.Web.WebSite.DeleteVirtualDirectory();

  37:          delVDirObject.MachineName          = machineName;

  38:          delVDirObject.VirtualDirectoryName = vDirToDelete;

  39:          delVDirObject.WebSiteName          = webSiteName;

  40:          if (delVDirObject.Execute()) {

  41:            Project.Log(Level.Info, "Auswipe.NAntTasks.VDirTasks : The VDir '" + vDirToDelete + "' was successful deleted.");

  42:          } else {

  43:            Project.Log(Level.Error, "Auswipe.NAntTasks.VDirTasks : ERROR: The VDir '" + vDirToDelete + "' was NOT deleted but an exception was not thrown.");

  44:          };

  45:        } catch (Exception e) {

  46:          Project.Log(Level.Error, "Auswipe.NAntTasks.VDirTasks : VDir deletion failed with the resulting exception:");

  47:          Project.Log(Level.Error, e.ToString());

  48:        };

  49:      }

  50:    }

  51:    #endregion

  52:    # region Create VDir

  53:    [TaskName("createvdir")]

  54:    public class CreateVDir : NAnt.Core.Task {

  55:      private string vDirName;

  56:      private string webSiteName;

  57:      private string appPoolName;

  58:      private string machineName;

  59:      private string fullPath;

  60:      [TaskAttribute("apppoolname", Required = true)]

  61:      [StringValidator(AllowEmpty = false)]

  62:      public string AppPoolName {

  63:        get { return appPoolName; }

  64:        set { appPoolName = value; }

  65:      }

  66:      [TaskAttribute("vdirname", Required = true)]

  67:      [StringValidator(AllowEmpty = false)]

  68:      public string VDirName {

  69:        get { return vDirName; }

  70:        set { vDirName = value; }

  71:      }

  72:      [TaskAttribute("website", Required = true)]

  73:      [StringValidator(AllowEmpty = false)]

  74:      public string WebSite {

  75:        get { return webSiteName; }

  76:        set { webSiteName = value; }

  77:      }

  78:      [TaskAttribute("machinename", Required = true)]

  79:      [StringValidator(AllowEmpty = false)]

  80:      public string MachineName {

  81:        get { return machineName; }

  82:        set { machineName = value; }

  83:      }

  84:      [TaskAttribute("path", Required = true)]

  85:      [StringValidator(AllowEmpty = false)]

  86:      public string FullPath {

  87:        get { return fullPath; }

  88:        set { fullPath = value; }

  89:      }

  90:      protected override void ExecuteTask() {

  91:        Project.Log(Level.Info, "Auswipe.NAntTasks.VDirTasks : The following VDir will be created: '" + vDirName + "'");

  92:        try {

  93:          Microsoft.Sdc.Tasks.Web.WebSite.CreateVirtualDirectory createVDirObject = new Microsoft.Sdc.Tasks.Web.WebSite.CreateVirtualDirectory();

  94:          createVDirObject.AppCreate            = true;

  95:          createVDirObject.AppPoolId            = appPoolName;

  96:          createVDirObject.MachineName          = machineName;

  97:          createVDirObject.VirtualDirectoryName = vDirName;

  98:          createVDirObject.WebSiteName          = webSiteName;

  99:          createVDirObject.Path                 = fullPath;

 100:          if (createVDirObject.Execute()) {

 101:            Project.Log(Level.Info, "Auswipe.NAntTasks.VDirTasks : The VDir '" + vDirName + "' was successfuly created.");

 102:          } else {

 103:            Project.Log(Level.Error, "Auswipe.NAntTasks.VDirTasks : ERROR: The VDir '" + vDirName + "' was NOT created but an exception was not thrown.");

 104:          };

 105:        } catch (Exception e) {

 106:          Project.Log(Level.Error, "Auswipe.NAntTasks.VDirTasks : VDir creation failed with the resulting exception:");

 107:          Project.Log(Level.Error, e.ToString());

 108:        };

 109:      }

 110:    }

 111:    #endregion

 112:  }



A caveat that I've found though is that even though the invoked SDC Task might run into a problem during the .Execute call, .Execute still returns a true so my NAnt task doesn't know if the process has ran into a problem.

In the example below, I'm trying to create a VDir with an AppPool that doesn't exist:

8<-------------------------------------------
NAnt 0.85 (Build 0.85.2478.0; release; 10/14/2006)
Copyright (C) 2001-2006 Gerry Shaw
http://nant.sourceforge.net

Buildfile: file:///C:/customtask/default.build
Target framework: Microsoft .NET Framework 2.0
Target(s) specified: test-task

[loadtasks] Scanning assembly "Auswipe.NAntTasks.VDirTasks" for extensions.
[loadtasks] Scanning assembly "Auswipe.NAntTasks.AppPoolTasks" for extensions.

test-task:

[echo] Creating VDir
Auswipe.NAntTasks.VDirTasks : The following VDir will be created: 'someVDir'
Creating virtual directory "someVDir".
A task error has occured.
Message = Exception has been thrown by the target of an invocation.
VirtualDirectoryName = someVDir
Path = c:\somewebsite
MachineName = Auswipel-rfs2we
WebSiteName = Default Web Site
WebAppName =
AppPoolId = AppPoolDoesNotExist
AppCreate = True
AnonymousUserName =
AnonymousUserPassword =
UncUserName =
UncPassword =
AuthFlags =
AccessFlags =

at System.DirectoryServices.DirectoryEntry.Invoke(String methodName, Object[] args)
at Microsoft.Sdc.Tasks.Configuration.Web.VirtualDirectory.AppCreate3() in c:\projects\codeplex\sdctasks\Solutions\Main\Tasks\Configuration\Web\VirtualDirectory.cs:line 324
at Microsoft.Sdc.Tasks.Web.WebSite.CreateVirtualDirectory.InternalExecute() in c:\projects\codeplex\sdctasks\Solutions\Main\Tasks\Web\WebSite\CreateVirtualDirectory.cs:line 315
at Microsoft.Sdc.Tasks.TaskBase.Execute() in c:\projects\codeplex\sdctasks\Solutions\Main\Tasks\TaskBase.cs:line 66
Element not found. (Exception from HRESULT: 0x80070490)

PseudoEngineException
at Microsoft.Sdc.Tasks.PseudoBuildEngine.LogErrorEvent(BuildErrorEventArgs eventArgs) in c:\projects\codeplex\sdctasks\Solutions\Main\Tasks\PseudoBuildEngine.cs:line 77
at Microsoft.Build.Utilities.TaskLoggingHelper.LogError(String subcategory, String errorCode, String helpKeyword, String file, Int32 lineNumber, Int32 columnNumber, Int32 endLineNumber, Int32 endColumnNumber, String message, Object[] messageArgs)
at Microsoft.Build.Utilities.TaskLoggingHelper.LogError(String message, Object[] messageArgs)
at Microsoft.Sdc.Tasks.TaskBase.Execute() in c:\projects\codeplex\sdctasks\Solutions\Main\Tasks\TaskBase.cs:line 95
Auswipe.NAntTasks.VDirTasks : VDir creation failed with the resulting exception:
System.ApplicationException: PseudoEngineException
at Microsoft.Sdc.Tasks.PseudoBuildEngine.LogErrorEvent(BuildErrorEventArgs eventArgs) in c:\projects\codeplex\sdctasks\Solutions\Main\Tasks\PseudoBuildEngine.cs:line 77
at Microsoft.Build.Utilities.TaskLoggingHelper.LogError(String subcategory, String errorCode, String helpKeyword, String file, Int32 lineNumber, Int32 columnNumber, Int32 endLineNumber, Int32 endColumnNumber, String message, Object[] messageArgs)
at Microsoft.Build.Utilities.TaskLoggingHelper.LogErrorFromException(Exception exception, Boolean showStackTrace, Boolean showDetail, String file)
at Microsoft.Build.Utilities.TaskLoggingHelper.LogErrorFromException(Exception exception, Boolean showStackTrace)
at Microsoft.Sdc.Tasks.TaskBase.Execute() in c:\projects\codeplex\sdctasks\Solutions\Main\Tasks\TaskBase.cs:line 99
at Auswipe.NAntTasks.VDirTasks.CreateVDir.ExecuteTask()

BUILD SUCCEEDED - 2 non-fatal error(s), 0 warning(s)

Total time: 0.2 seconds.
------------------------------------------->8

You would think that .Execute should return a False for the call but it doesn't. Notice the verbage of "2 non-fatal error(s)" so it appears that the SDC Task does not treat the non-existant Applicaiton Pool as a fatal error. Good to know!

Going back and looking at the IIS Manager we see this for the create VDir:



Notice how the Application Pool is set to "<Invalid Application Pool>."

So, the VDir was created, despite the lack of a valid Application Pool. That's something to be aware of when testing out NAnt tasks that wrap SDC Task functionality.

No comments: