【问题标题】:How to capture DacSevices.Deploy output?如何捕获 DacServices.Deploy 输出?
【发布时间】:2015-09-29 16:25:25
【问题描述】:

所以我设法部署了我们的DACPAC schema via Octopus。我正在使用与.Net 对象交互的 Deploy.ps1 脚本,就像文章描述的那样。

我想通过在我们的 Octopus 日志中包含您从 sqlcmd 获得的“标准输出”来使部署过程更加透明。我正在寻找生成的模式修改消息以及我们的开发人员已放入 pre/post 脚本的任何自定义迁移迁移消息。

我能想到的唯一解决方法是首先使用 DACPAC 服务生成脚本,然后使用 sqlcmd.exe 运行它。有什么想法吗?

【问题讨论】:

    标签: sql-server dacpac


    【解决方案1】:

    找到解决方案,发布以防其他人遇到此问题。您只需订阅您的 DacService 的Message event

    C# 示例:

    var services = new Microsoft.SqlServer.Dac.DacServices("data source=machinename;Database=ComicBookGuy;Trusted_connection=true");
    
    var package = Microsoft.SqlServer.Dac.DacPackage.Load(@"C:\Database.dacpac");
    
    var options = new Microsoft.SqlServer.Dac.DacDeployOptions();
    options.DropObjectsNotInSource = true;
    options.SqlCommandVariableValues.Add("LoginName", "SomeFakeLogin");
    options.SqlCommandVariableValues.Add("LoginPassword", "foobar!");
    
    services.Message += (object sender, Microsoft.SqlServer.Dac.DacMessageEventArgs eventArgs) => Console.WriteLine(eventArgs.Message.Message);
    
    services.Deploy(package, "ComicBookGuy", true, options);
    

    Powershell 示例(由章鱼触手执行):

    # This script is run by Octopus on the tentacle
    $localDirectory = (Get-Location).Path
    $tagetServer = $OctopusParameters["SQL.TargetServer"]
    $databaseName = "ComicBookGuy"
    
    Add-Type -path "$localDirectory\lib\Microsoft.SqlServer.Dac.dll"
    
    $dacServices = New-Object Microsoft.SqlServer.Dac.DacServices ("data source=" + $tagetServer + ";Database=" + $databaseName + "; Trusted_connection=true")
    $dacpacFile = "$localDirectory\Content\Unity.Quotes.Database.dacpac"
    
    $dacPackage = [Microsoft.SqlServer.Dac.DacPackage]::Load($dacpacFile)
    
    $options = New-Object Microsoft.SqlServer.Dac.DacDeployOptions
    $options.SqlCommandVariableValues.Add("LoginName", $OctopusParameters["SQL.LoginName"])
    $options.SqlCommandVariableValues.Add("LoginPassword", $OctopusParameters["SQL.LoginPassword"])
    $options.DropObjectsNotInSource = $true
    
    Register-ObjectEvent -InputObject $dacServices -EventName "Message" -Action { Write-Host $EventArgs.Message.Message } | out-null
    
    $dacServices.Deploy($dacPackage, $databaseName, $true, $options)
    

    在 powershell 版本中,我无法使用方便的“Add_EventName”样式的事件通知,因此我不得不使用笨重的 cmdlet。嗯。

    【讨论】:

    • 我刚刚尝试过,它使用 C# 和 DacPac 程序集按预期工作。很好的答案!
    • 值得注意的是,Register-ObjectEvent 是异步工作的,因此,主脚本不会等待 Register-ObjectEvent 行来处理所有消息,并且可能会在显示所有事件之前完成。
    • 与 SqlPackage.exe 不同,当使用 powershell 运行时,即使注册了这些事件,它们似乎也只会在最后一次在 StdOut 中报告,而不是实时报告。这意味着,如果您正在等待长时间运行的 postdeploy,则不清楚正在运行哪个。
    【解决方案2】:

    使用 sqlpackage 代替 sqlcmd 来部署 dacpac。

    在这里获取最新版本:https://msdn.microsoft.com/en-us/mt186501

    $sqlpackage = "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\120\sqlpackage.exe"
    

    它会自动在控制台输出错误。我们使用 TFS 构建定义并调用 powershell,它能够显示部署期间发生的错误。

    用法:

    & $sqlpackage /Action:Publish /tsn:$dbServer /tdn:$database /sf:$mydacpac/pr:$dbProfile /variables:myVariable=1
    

    【讨论】:

    • 这是一个明智的选择有EXE。感谢您的意见!
    • 大卫,是的,API 也很好用。我们在从后端执行脚本时使用它,但我们主要在较低环境中使用自助部署,并且 TFS 构建定义能够正确捕获错误。直接从 powershell 运行 EXE 效果不好。
    • 这是一个很好的解决方案!
    【解决方案3】:

    此变体捕获输出,但还允许您通过捕获异常来捕获部署失败并做出反应

    function Load-DacPacAssembly()
    {
        $assemblyName = "Microsoft.SqlServer.Dac.dll"
        $packageFolder = <some custom code to find our package folder>
        $dacPacAssembly = "$packageFolder\lib\net46\$assemblyName"
    
        Write-Host "Loading assembly $assemblyName"
        Add-Type -Path "$dacPacAssembly" 
    }
    
    function Publish-Dacpac($dacpac, $publishProfile){
    
        Load-DacPacAssembly
    
        Write-Host "Loading profile $publishProfile..."
        $dacProfile = [Microsoft.SqlServer.Dac.DacProfile]::Load($publishProfile)
        $dacService = New-Object Microsoft.SqlServer.dac.dacservices ($dacProfile.TargetConnectionString)
    
        Write-Host "Loading dacpac $dacpac"
        $dacPackage = [Microsoft.SqlServer.Dac.DacPackage]::Load($dacpac)
    
        $event = Register-ObjectEvent -InputObject $dacService -EventName "Message" -Action { 
            $message = $EventArgs.Message
            $colour = "DarkGray"
            if ($message -contains "Error SQL")
            {
                $colour = "Red"
            }
    
            Write-Host $message -ForegroundColor $colour
        }
    
        Write-Host "Publishing...."
    
        try {
            $dacService.deploy($dacPackage, $dacProfile.TargetDatabaseName, $true, $dacProfile.DeployOptions)
        }
        catch [Microsoft.SqlServer.Dac.DacServicesException]
        {        
            $message = $_.Exception.Message
            Write-Host "SQL Publish failed - $message" -ForegroundColor Red # Customise here for your build system to detect the error
            exit;
        }
        finally
        {
            Unregister-Event -SourceIdentifier $event.Name
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-01
      • 2012-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多