【问题标题】:Using custom Task in CC.net configuration在 CC.net 配置中使用自定义任务
【发布时间】:2012-07-16 16:36:18
【问题描述】:

我为 Cruise Control .net 创建了以下自定义任务,但我找不到有关如何将自定义任务添加到项目配置的单一参考。有没有人有一个有用的例子来说明如何在 cc.net 中添加对自定义任务的引用?

(以下是我的新任务)

public class RestoreDb : TaskBase
{
    #region Parameters

    [Required]
    public string ServerName { get; set; }
    [Required]
    public string DbName { get; set; }

    public string BackupFileName { get; set; }

    #endregion

    protected override bool Execute(ThoughtWorks.CruiseControl.Core.IIntegrationResult result)
    {
        bool returnResult = false;
        try
        {
            SqlConnectionStringBuilder connectionStringBuilder = new SqlConnectionStringBuilder();
            connectionStringBuilder.IntegratedSecurity = true;
            connectionStringBuilder.DataSource = ServerName;
            SqlConnection connection = new SqlConnection(connectionStringBuilder.ToString());
            connection.Open();

            Server server = new Server(new ServerConnection(connection));

            if (server.Databases[DbName] != null)
            {
                Log.Info("Dropping existing " + DbName + " on " + ServerName);
                server.Databases[DbName].Drop();
            }
            else
            {
                Log.Info(DbName + " on " + ServerName + " doesn't exist.");
            }

            Log.Info("Restoring " + DbName + " on " + ServerName);
            Database newDb = new Database(server, DbName);

            Restore rs = new Restore();
            rs.NoRecovery = false;

            FileInfo fi = new FileInfo(server.Settings.BackupDirectory + "\\" + BackupFileName);
            rs.Devices.AddDevice(fi.FullName, DeviceType.File);
            rs.Database = DbName;
            rs.Action = RestoreActionType.Database;
            rs.ReplaceDatabase = true;

            DataTable fileContents = rs.ReadFileList(server);
            string originalDbName = fileContents.Rows[0][0].ToString();
            string originalLogFileName = fileContents.Rows[1][0].ToString();
            rs.RelocateFiles.Add(new RelocateFile(originalDbName, 
            string.Format(@"C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA\{0}.mdf", DbName)));

            rs.RelocateFiles.Add(new RelocateFile(originalLogFileName,
            string.Format(@"C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA\{0}_1.ldf", DbName)));

            rs.SqlRestore(server);
            Log.Info("Restoring done.");
            returnResult = true; // success!
        }
        catch (Exception ex)
        {
            Log.Error(ex);
            returnResult = false;
        }
        return returnResult;
    }
}

【问题讨论】:

    标签: cruisecontrol.net


    【解决方案1】:

    您没有提到您正在使用的版本,所以我假设用户将使用更新版本来回答这个问题。我是根据为 1.8.3.0 开发自定义任务的经验构建的

    您可以在此处找到一些用于创建和使用 http://www.cruisecontrolnet.org/projects/ccnet/wiki/DevInfo_MakingPlugins

    编辑:我想指出,所提供链接上的 CruiseControl.NET 文档已更新,现在包含此处包含的大部分信息。

    但是,此文档的重量相当轻,并没有真正涵盖您在尝试创建自己的任务时最终会遇到问题的主题范围。

    过程,我可以简单地说;

    • 您的自定义任务项目需要引用以下程序集,这些程序集可以在 CruiseControl.NET 服务器根文件夹中找到。

      • NetReflector.dll
      • ThoughtWorks.CruiseControl.Core.Dll
      • 您引用的任何其他不属于 .NET 3.5 框架的程序集
    • 在构建自定义任务时,您需要使用反射器属性标记您希望公开的任何类或属性,以使其在 ccnet.config 中可用

    • 为了让 CruiseControl.NET 使用您的自定义库,您需要使用以下约定命名程序集:ccnet.WhateverYouWantHere.plugin.dll

    • 您需要将此程序集放在您的 CruiseControl.NET 服务器文件夹中。

      • 如果您通过在 ccnet.exe.config 中为 PluginLocation 提供值来设置插件目录,则需要将程序集放置在那里。
      • 您在项目中引用的任何尚未在 CruiseControl.NET 服务器文件夹中的程序集也需要添加到服务器或插件文件夹中
    namespace MyTasks
    {
        [ReflectorType("MyCustomTask")]
        public class MyCustomTaskClass : ITask 
        {
            [ReflectorProperty("MyCustomTaskProperty")]
            public string CustomProperty { get; set; }
    
            public string MyInternalPublicProperty { get; set; }
    
            public void Run(IIntegrationResult result){}
        }
    }
    

    注意:属性名称和您向 ccnet.config 公开的名称不必匹配。

    为了引用创建的任务、标注器等,您只需使用反射器属性中提供的字符串。

    <project>
        <tasks>
            <MyCustomTask MyCustomTaskProperty="This is an example"/>
        </tasks>
    </project>
    

    如果您尝试使用此代码,并在您的标签中添加对 MyInternalPublicProperty 的引用,它将不起作用:

    <project>
        <tasks>
            <MyCustomTask MyInternalPublicProperty="This is will throw an exception in the service and not reload the ccnet config until the invalid content is removed from the config"/>
        </tasks>
    </project>
    

    这是因为你没有用它自己的 [ReflectorProperty()] 属性来装饰属性。

    【讨论】:

      【解决方案2】:

      所以我基本上放弃了这个,因为在任何地方都没有关于如何将自定义任务添加到 cc.net 配置的示例。下面是我编写的 powershell 脚本,它执行完全相同的步骤。

      $ServerName = 'servernamehere';
      $DatabaseName = 'newDbNameHere';
      $BackupFile = 'C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\Backup\backupFileHere.bak';
      if($args[0])
      {
          $ServerName = $args[0];
      }
      if($args[1])
      {
          $DatabaseName = $args[1];
      }
      if($args[2])
      {
          $BackupFile = $args[2];
      }
      
      [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo")
      [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.SmoExtended")
      try 
      {
          $Server = new-object ("Microsoft.SqlServer.Management.Smo.Server") $ServerName
      
          If ($Server.Databases.Contains($DatabaseName))
          {
              write-host "Dropping existing " $DatabaseName " on " $ServerName;
              #$Server.Databases[$DatabaseName].SetOffline();
              $Server.Databases[$DatabaseName].Drop();
          }
          else
          {
              write-host $DatabaseName " on " $ServerName " doesn't exist.";
          }
          $Database = new-object ("Microsoft.SqlServer.Management.Smo.Database") ($Server, $DatabaseName);
      
          $restore = new-object ('Microsoft.SqlServer.Management.Smo.Restore');
          $restore.NoRecovery = $false;
      
          $fil=new-object "Microsoft.SqlServer.Management.Smo.BackupDeviceItem";
          $fil.DeviceType='File';
          $fil.Name= $BackupFile;
          $restore.Action="Database";
          $restore.Devices.Add($fil);
          $restore.Database=$DatabaseName;
          $restore.ReplaceDatabase = $true;
      
          #retrieving the backup file's original database values so we can replace them
          $FileContents = $restore.ReadFileList($Server);
          $originalDbName =  $FileContents.Rows[0][0].ToString();
          $originalLogFileName = $FileContents.Rows[1][0].ToString();
      
          #replacing the bak files original file names with the new file names
          $mdf = new-object "Microsoft.SqlServer.Management.Smo.RelocateFile" ($originalDbName,
              "C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA\$DatabaseName.mdf");
          $restore.RelocateFiles.Add($mdf);
          $ldf = new-object "Microsoft.SqlServer.Management.Smo.RelocateFile" ($originalLogFileName,
              "C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA\$DatabaseName_Log.mdf");
          $restore.RelocateFiles.Add($ldf);
      
      
          write-host "Restoring database $DatabaseName  on  $ServerName from file $BackupFile";
      
              $restore.SqlRestore($Server);
              write-host "Restore Complete";
      }
      catch [System.Exception] {
        # $_ is set to the ErrorRecord of the exception
        $currentException = $_.Exception;
        write-host "Root Exception: " $currentException.Message;
        While($currentException.InnerException)
        {
          $currentException = $_.Exception.InnerException;
          write-host "Inner Exception: " $currentException.Message;
        }
        write-host "Restore Failed.";
        exit 0; #failure
      }    
      exit 1;
      

      【讨论】:

      • 这真的不是您发布的问题的答案
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-05-04
      • 1970-01-01
      • 2013-01-31
      • 1970-01-01
      • 1970-01-01
      • 2014-06-03
      • 1970-01-01
      相关资源
      最近更新 更多