使用WIX创建安装程序时执行sqlpackage.exe(几乎没有依赖dll)

时间:2014-09-01 11:04:12

标签: c# wix dacpac

我需要在使用WIX安装数据库时部署dacpac。为此,我考虑使用必要的开关运行SQLPackage.exe命令,所以我使用二进制标签嵌入了必要的exe和dll,如下所示

<Binary Id="Microsoft.Data.Tools.Schema.Sql.dll" SourceFile="..\DeployDBs\DAC\Microsoft.Data.Tools.Schema.Sql.dll"/>
    <Binary Id="Microsoft.Data.Tools.Schema.Tasks.Sql.11.dll" SourceFile="..\DeployDBs\DAC\Microsoft.Data.Tools.Schema.Tasks.Sql.11.dll"/>
    <Binary Id="Microsoft.Data.Tools.Schema.Utilities.Sql.11.dll" SourceFile="..\DeployDBs\DAC\Microsoft.Data.Tools.Schema.Utilities.Sql.11.dll"/>
    <Binary Id="Microsoft.Data.Tools.Utilities.dll" SourceFile="..\DeployDBs\DAC\Microsoft.Data.Tools.Utilities.dll"/>
    <Binary Id="Microsoft.SqlServer.Dac.dll" SourceFile="..\DeployDBs\DAC\Microsoft.SqlServer.Dac.dll"/>
    <Binary Id="SqlPackage" SourceFile="..\DeployDBs\DAC\SqlPackage.exe"/>
    <Binary Id="SqlPackage.exe.config" SourceFile="..\DeployDBs\DAC\SqlPackage.exe.config"/>

使用自定义操作调用SqlPackage.exe,如下所示

 <CustomAction Id="DeployMyDb" BinaryKey="SqlPackage" 
              ExeCommand="/a:publish /sf:&quot;MyDacpac.dacpac&quot; /tsn:localhost /tdn:MyDb" 
              Execute="immediate" />

自定义操作是在&#39; InstallFinalize&#39;之后运行的序列。如下

<InstallExecuteSequence>
      <Custom Action="DeployMyDb" After="InstallFinalize"/>
    </InstallExecuteSequence>
    </Product>

当部署dacpac时(即运行自定义操作),它会抛出&#39; FileNotFoundException&#39;对于汇编&#39; Microsoft.Data.Tools.Utilities,它是嵌入式二进制文件之一。

请告知缺少的步骤或添加要运行此exe所需的内容。

2 个答案:

答案 0 :(得分:3)

我找到了解决方案。

我没有采用上述方法,而是为自定义操作创建了一个单独的项目,并添加了对所需二进制文件的引用(即我之前在&lt; binary&gt;标记中提到的二进制文件)并添加了二进制标记中形成的相应dll并调用了通过&lt; CustomAction&gt;

所得溶液如下:

<Binary Id="InstallerWix_CustomAction.CA.dll" SourceFile="..\InstallerWix_CustomAction\bin\Debug\InstallerWix_CustomAction.CA.dll" />

<CustomAction Id="DeployDb" BinaryKey="InstallerWix_CustomAction.CA.dll" 
                 DllEntry="CustomAction1"                   
                  Execute="immediate" Return="check" />

<InstallExecuteSequence>
  <Custom Action="DeployDb" After="InstallFinalize"/>
</InstallExecuteSequence>

答案 1 :(得分:2)

我能够通过将dacpac文件添加为二进制文件,在CustomAction中读取该二进制文件,最后在我的C#自定义操作中使用'Microsoft.SqlServer.Dac'(在nuget上可用)来实现此功能。

我必须将二进制文件流写入MemoryStream以与DacPac.Load函数一起使用。二进制流是内部类型的“RecordStream”,Load函数无法使用它。出于您的目的,您可能还需要修改dacOptions变量以获得所需的结果。

请参阅下面的示例:

Project.wxs:

<Binary Id="Database.dacpac" SourceFile="$(var.ProjectDir)\Database.dacpac" />

<CustomAction Id="DeployDacpac" BinaryKey="CustomAction.dll" DllEntry="DeployDacpac" Execute="immediate" />

<InstallExecuteSequence>
  <Custom Action="DeployDacpac" After="InstallFinalize" />
</InstallExecuteSequence>

CustomAction.cs:

[CustomAction]
    public static ActionResult DeployDacpac(Session session)
    {
        try
        {
            string sql = string.Format("SELECT Data FROM Binary WHERE Name = 'Database.dacpac'");

            View view = session.Database.OpenView(sql);

            view.Execute();
            var dataStream = view.First()["Data"] as Stream;
            byte[] buffer = new byte[dataStream.Length];
            int bytesRead;
            while ((bytesRead = dataStream.Read(buffer, 0, buffer.Length)) > 0) ;
            using (MemoryStream ms = new MemoryStream(buffer))
            {
                var dacOptions = new DacDeployOptions();
                dacOptions.BlockOnPossibleDataLoss = false;
                dacOptions.DropDmlTriggersNotInSource = false;
                dacOptions.DropObjectsNotInSource = false;

                var dacServiceInstance = new DacServices(GenerateConnectionString(session["SQLSERVER"], session["SQLDATABASE"], session["SQLUSER"], session["SQLPASSWORD"]));
                using (DacPackage dacpac = DacPackage.Load(ms))
                {
                    dacServiceInstance.Deploy(dacpac, session["SQLDATABASE"], upgradeExisting: true, options: dacOptions);
                }
            }
        }
        catch (Exception ex)
        {
            session.Log(ex.Message);
            return ActionResult.Failure;
        }
        return ActionResult.Success;
    }