为 Package Deployer 工具创建数据包

Package Deployer 使管理员能够在 Microsoft Dataverse 实例上部署数据包。 一个 Package Deployer 可以包括以下任意或全部内容:

  • 一个或多个 Dataverse 解决方案文件。
  • 平面文件或从配置迁移工具中导出的配置数据文件。 有关此工具的详细信息,请参阅使用配置迁移工具跨实例和组织移动配置数据
  • 在将数据包部署到 Dataverse 实例之前、期间或在部署好之后可运行的自定义代码。
  • 针对在部署流程开始和结束时显示的数据包的 HTML 内容。 此内容将有助于提供在数据包中部署的解决方案和文件的说明。

备注

还有另一种包类型称为插件包。 这种类型的包适用于依赖于插件的程序集,与 Package Deployer 包没有关系。

先决条件

  • 确保您已准备好要包括在包中的所有解决方案及其他文件。
  • Visual Studio 2019 或更高版本,或 Visual Studio Code。

流程概述

要创建 Package Deployer 包,请执行以下步骤。

  • 创建 Visual Studio 或 MSBuild 项目
  • 向项目添加解决方案和其他文件
  • 更新提供的 HTML 文件(可选)
  • 为包指定配置值
  • 为包定义自定义代码
  • 构建并部署包

本文将详细介绍这些步骤。

创建包项目

第一步是为包创建 Visual Studio 或 MSBuild 项目。 为此,您必须在开发计算机上安装两个可用的工具扩展之一。 如果使用 Visual Studio Code,安装 Microsoft Power Platform CLI。 否则,如果使用 Visual Studio 2019,则安装用于 Visual Studio 的 Power Platform tools。 Power Platform tools 扩展目前仅适用于 Visual Studio 2019。 但是,创建的项目可以使用 Visual Studio 2019 或更高版本构建。

选择下面的相应选项卡,了解如何使用所需的工具扩展创建项目。 这两个工具以相似格式输出项目。

运行 pac package init 命令创建初始包。 详细信息:pac package

pac package init help
pac package init --outputDirectory DeploymentPackage

生成的 CLI 输出包含如下所示的文件夹和文件。 此处使用“DeploymentPackage”文件夹名称作为示例。

C:.
└───DeploymentPackage
    │   DeploymentPackage.csproj
    │   PackageImportExtension.cs
    │
    └───PkgAssets
            ImportConfig.xml
            manifest.ppkg.json

在创建的项目中,找到 PkgAssets 文件夹中的 ImportConfig.xml 配置文件和 PackageImportExtension.cs 文件。 您将按照本文后面的描述修改这些文件。

添加包文件

创建包项目后,可以开始向该项目添加解决方案和其他文件。

使用 CLI 时,可以使用 add 子命令之一将外部包、解决方案和引用添加到包项目。 输入 pac package help 可以查看子命令列表。 我们来向包中添加一个解决方案。

> pac package add-solution help

Commands:
Usage: pac package add-solution --path [--import-order] [--skip-validation] [--publish-workflows-activate-plugins] [--overwrite-unmanaged-customizations] [--import-mode] [--missing-dependency-behavior] [--dependency-overrides]

> cd .\DeploymentPackage\
> pac package add-solution --path ..\TestSolution_1_0_0_1_managed.zip

The item was added successfully.

配置包

  1. 通过在项目中的 ImportConfig.xml 文件中添加关于包的信息来定义包配置。 打开文件进行编辑。 下面的列表提供了有关配置文件中的每个参数和节点的信息。

    installsampledata
    Truefalse。 如果 true,将示例数据安装到 Dataverse 实例。 此数据是您可以从 Dataverse 中的设置>数据管理区域中安装的同一个示例数据。

    waitforsampledatatoinstall
    truefalse。 如果为 true 并且 installsampledata 也被设置为 true,则在部署数据包之前等待示例数据安装。

    备注

    如果将 waitforsampledatatoinstall 设置为 true,请确保您将 installsampledata 设置为 true

    agentdesktopzipfile
    打开要解压缩的的压缩文件的文件名。 如果在此指定一个 .zip 文件名,在提示您选择一个要在其解压缩文件内容的位置的数据包部署过程期间,添加一个屏幕。

    此属性通常用于为 Unified Service Desk for Dynamics 365 创建包。 有关 Unified Service Desk 的信息,请参阅 Unified Service Desk 3.0 管理指南

    agentdesktopexename
    在部署过程快结束时调用位于压缩文件或 URL 中的 .exe 或 .msi 文件的名称。

    此属性通常用于为 Unified Service Desk 创建包。

    crmmigdataimportfile
    使用配置迁移工具导出的默认配置数据文件 (.zip) 的文件名。

    • 您还可以基于在运行 Package Deployer 时使用新运行时设置指定的区域 ID (LCID) 导入配置数据文件的本地化版本。 使用 <cmtdatafile> 节点(下文进行解释)在数据包中指定配置数据文件的本地化版本,再使用 OverrideConfigurationDataFileLanguage 方法(下文进行解释)指定基于使用运行时设置指定的区域 ID 导入配置数据文件的逻辑。 不能一次使用一个包导入多个配置数据文件。

    • 对于 Dataverse(内部部署),如果您的配置数据文件包含用户信息,且源和目标 Dataverse 实例位于同一 Active Directory 域,用户信息将导入到目标 Dataverse 实例。 若要导入用户信息到其他域中的 Dataverse(内部部署)实例,则您必须在您的项目中包括使用配置迁移工具生成的用户映射文件 (.xml),并在稍后所述的 <cmtdatafile> 节点中使用 usermapfilename 属性指定它以及配置数据文件。 用户信息不能导入到 Dataverse 实例。
      <solutions> 节点
      包含要导入的描述解决方案的 <configsolutionfile> 阵列。 该节点下的解决方案的顺序指示了将解决方案导入目标 Dataverse 实例要遵循的顺序。

      <configsolutionfile> 节点
      使用 <solutions> 节点下的此节点指定单独的解决方案以及要导入的每个解决方案的以下信息:

    • solutionpackagefilename:指定您的解决方案的 .zip 文件名。 必需。

    • overwriteunmanagedcustomizations:指定在导入已存在于目标 Dynamics 365 实例的解决方案时,是否覆盖任何非托管的自定义项。 此属性是可选的,如果您没有指定此属性,默认情况下现有解决方案的非托管自定义项将在目标 Dynamics 365 实例中保留。

    • publishworkflowsandactivateplugins:指定导入解决方案后,是否在目标 Dynamics 365 实例中发布工作流和激活插件。 此属性是可选的,如果没有指定此属性,默认情况下,在解决方案导入到目标 Dynamics 365 实例后,工作流将发布且插件将被激活。

      您可以通过在数据包中添加多个 <configsolutionfile> 节点来添加多个解决方案文件名。 例如,若要导入三个解决方案文件,请按照以下方式添加:

    
    <solutions>  
    <configsolutionfile solutionpackagefilename="SampleSolutionOne_1_0_managed.zip"  
    overwriteunmanagedcustomizations="false"  
    publishworkflowsandactivateplugins="true"/>  
    <configsolutionfile solutionpackagefilename="SampleSolutionTwo_1_0_managed.zip"  
    overwriteunmanagedcustomizations="false"  
    publishworkflowsandactivateplugins="true"/>  
    <configsolutionfile solutionpackagefilename="SampleSolutionThree_1_0_managed.zip" />  
    </solutions>  
    
    

    <filestoimport> 节点
    包含用于分别描述要导入的每个文件和压缩文件的 <configimportfile> 阵列和 <zipimportdetails> 节点。

    <configimportfile> 节点
    使用 <configimportfile> 节点下的该节点描述要导入到 Dataverse 的文件。 您可以通过在数据包中添加多个 <configimportfile> 节点来添加多个文件。

    
    <filestoimport>  
    <configimportfile filename="File.csv"  
    filetype="CSV"  
    associatedmap="FileMap"  
    importtoentity="FileEntity"  
    datadelimiter=""  
    fielddelimiter="comma"  
    enableduplicatedetection="true"  
    isfirstrowheader="true"  
    isrecordownerateam="false"  
    owneruser=""  
    waitforimporttocomplete="true" />  
    <configimportfile filename="File.zip"  
    filetype="ZIP"  
    associatedmap="FileMapName"  
    importtoentity="FileEntity"  
    datadelimiter=""  
    fielddelimiter="comma"  
    enableduplicatedetection="true"  
    isfirstrowheader="true"  
    isrecordownerateam="false"  
    owneruser=""  
    waitforimporttocomplete="true"/>  
    
    </filestoimport>  
    
    

    下面是受支持属性列表:

    属性 说明
    filename 包含导入数据的文件名称。 如果文件是 .zip 文件,<zipimportdetails> 节点必须为 .zip 中的每个文件提供 <zipimportdetail> 节点。
    filetype 此值可以是 csv、xml 或 zip。
    associatedmap 使用此文件的 Dataverse 导入数据映射的名称。 如果为空,则为此文件尝试使用系统决定的导入数据映射。
    importtoentity 可以是压缩文件中的 exe、URL 或 .msi 文件名称,在过程末尾调用链接。
    datadelimiter 导入文件中所使用的数据分隔符的名称。 有效值为“单引号”或“双引号”。
    fielddelimiter 导入文件中所使用的字段分隔符的名称。 有效值为“逗号”或“冒号”或“单引号”。
    enableduplicatedetection 指示是否对数据导入启用重复检测功能。 有效值为 truefalse
    isfirstrowheader 用于指示导入文件的第一行包含字段名称。 有效值是 truefalse
    isrecordownerateam 指示导入记录的所有者是否应为团队。 有效值是 truefalse
    owneruser 指示应拥有记录的用户 ID。 默认值是当前登录用户。
    waitforimporttocomplete 如果 true,则系统在继续之前等待导入完成。 如果 false,则对作业进行排队然后继续。

    <zipimportdetails> 节点
    该节点包含一个描述包含在用于导入到 Dynamics 365 中的压缩文件中的 <zipimportdetail> 节点阵列。

    <zipimportdetail> 节点
    使用 <zipimportdetails> 节点下的该节点提供在 <configimportfile> 节点中指定的 .zip 文件中的单个文件的信息。

    <filestoimport>  
    ...  
    ...  
    <zipimportdetails>  
    <zipimportdetail filename="subfile1.csv" filetype="csv" importtoentity="account" />  
    <zipimportdetail filename="subfile2.csv" filetype="csv" importtoentity="contact" />  
    </zipimportdetails>  
    </filestoimport>  
    
    

    支持的属性如下所示:

    属性 说明
    filename 包含导入数据的文件名称。
    filetype 此值可以是 csv 或 xml。
    importtoentity 可以是压缩文件中的 exe、url 或 MSI 文件名称,在过程末尾调用链接。

    <filesmapstoimport> 节点
    此节点包含要导入的 <configmapimportfile> 节点阵列。 该节点中映射文件的的顺序指示文件的导入顺序。 有关数据映射的信息,请参阅创建要导入的数据映射

    <configimportmapfile> 节点
    使用 <filesmapstoimport> 节点下的该节点提供有关将单个映射文件导入到 Dataverse 的信息。

    <filesmapstoimport>  
    <configimportmapfile filename="FileMap.xml" />  
    </filesmapstoimport>  
    

    <cmtdatafiles> 节点
    该节点包括包含要导入的配置数据文件的本地化版本的 <cmtdatafile> 节点阵列。

    <cmtdatafile> 节点
    <cmtdatafiles> 节点下使用此节点指定本地化配置数据文件与区域 ID(必需)和用户信息映射文件(可选)。 例如:

    <cmtdatafiles>  
    <cmtdatafile filename="data_1033.zip" lcid="1033" usermapfilename="UserMap.xml" />  
    <cmtdatafile filename="data_1041.zip" lcid="1041" usermapfilename="" />  
    </cmtdatafiles>  
    

    您可以使用 OverrideConfigurationDataFileLanguage 方法(下文进行解释)定义您的自定义逻辑,以基于使用运行时设置(下文进行解释)指定的区域 ID (LCID) 值导入本地化配置数据文件而不是默认文件(在 crmmigdataimportfile 中指定)。

  2. 选择保存全部

    以下 xml 表示示例 ImportConfig.xml 文件的内容。

    <?xml version="1.0" encoding="utf-16"?>  
    <configdatastorage xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"  
    xmlns:xsd="https://www.w3.org/2001/XMLSchema"  
    installsampledata="true"  
    waitforsampledatatoinstall="true"  
    agentdesktopzipfile=""  
    agentdesktopexename=""  
    crmmigdataimportfile="data_1033.zip">  
    <solutions>  
    <configsolutionfile solutionpackagefilename="SampleSolutionOne_1_0_managed.zip"  
    overwriteunmanagedcustomizations="false"  
    publishworkflowsandactivateplugins="true"/>  
    <configsolutionfile solutionpackagefilename="SampleSolutionTwo_1_0_managed.zip"  
    overwriteunmanagedcustomizations="false"  
    publishworkflowsandactivateplugins="true"/>  
    <configsolutionfile solutionpackagefilename="SampleSolutionThree_1_0_managed.zip" />  
    </solutions>  
    <filestoimport>  
    <configimportfile filename="SampleOption.csv"  
    filetype="CSV"  
    associatedmap="SampleOption"  
    importtoentity="sample_option"  
    datadelimiter=""  
    fielddelimiter="comma"  
    enableduplicatedetection="true"  
    isfirstrowheader="true"  
    isrecordownerateam="false"  
    owneruser=""  
    waitforimporttocomplete="false"/>  
    <configimportfile filename="File.zip"  
    filetype="ZIP"  
    associatedmap="FileMapName"  
    importtoentity="FileEntity"  
    datadelimiter=""  
    fielddelimiter="comma"  
    enableduplicatedetection="true"  
    isfirstrowheader="true"  
    isrecordownerateam="false"  
    owneruser=""  
    waitforimporttocomplete="true"/>  
    <zipimportdetails>  
    <zipimportdetail filename="subfile1.csv"  
    filetype="csv"  
    importtoentity="account" />  
    <zipimportdetail filename="subfile2.csv"  
    filetype="csv"  
    importtoentity="contact" />  
    </zipimportdetails>  
    </filestoimport>  
    <filesmapstoimport>  
    <configimportmapfile filename="SampleOption.xml" />  
    </filesmapstoimport>  
    <cmtdatafiles>  
    <cmtdatafile filename="data_1033.zip"  
    lcid="1033"  
    usermapfilename="UserMap.xml" />  
    <cmtdatafile filename="data_1041.zip"  
    lcid="1041"  
    usermapfilename="" />  
    </cmtdatafiles>  
    </configdatastorage>  
    
    

添加自定义代码

您可以添加在包导入环境之前、期间和之后执行的自定义代码。 要添加,请按照以下说明操作。

  1. 编辑项目根文件夹中的 PackageTemplate.cs(或 PackageImportExtension.cs)文件。

  2. 在 C# 文件中,您可以:

    1. InitializeCustomExtension 的覆盖方法定义中初始化数据包时,输入要执行的自定义代码。

      此方法可用于使用户在运行程序包时使用运行时参数。 作为开发人员,只要您有可以基于用户输入进行处理的代码,您便可以使用 RuntimeSettings 属性将任何运行时参数的支持添加到您的包。

      例如,以下示例代码为具有两个可能值的包启用名为 SkipChecks 的运行时参数:true 或 false。 示例代码检查用户是否在运行 Package Deployer 时指定任何运行时参数(使用命令行或 PowerShell),然后据此处理信息。 如果运行时参数由用户在运行包时指定,RuntimeSettings 属性的值将是 null。

      public override void InitializeCustomExtension()  
      {  
      // Do nothing.  
      
      // Validate the state of the runtime settings object.  
      if (RuntimeSettings != null)  
      {  
      PackageLog.Log(string.Format("Runtime Settings populated.  Count = {0}", RuntimeSettings.Count));  
      foreach (var setting in RuntimeSettings)  
      {  
      PackageLog.Log(string.Format("Key={0} | Value={1}", setting.Key, setting.Value.ToString()));  
      }  
      
      // Check to see if skip checks is present.  
      if ( RuntimeSettings.ContainsKey("SkipChecks") )  
      {  
      bool bSkipChecks = false;  
      if (bool.TryParse((string)RuntimeSettings["SkipChecks"], out bSkipChecks))  
      OverrideDataImportSafetyChecks = bSkipChecks;  
      }  
      }  
      else  
      PackageLog.Log("Runtime Settings not populated");  
      }  
      

      此代码让管理员可以使用命令行或 Import-CrmPackage cmdlet 指定是否在运行 Package Deployer 工具以导入包时跳过安全检查。 详细信息:使用 Package Deployer 和 Windows PowerShell 部署数据包

    2. 在解决方案在 PreSolutionImport 的替代方法定义中导入前,输入要执行的自定义代码以指定是否在更新目标 Dataverse 实例中的指定解决方案时保留或覆盖自定义项,以及是否自动激活插件和工作流。

    3. 使用 RunSolutionUpgradeMigrationStep 的替代方法定义在两个解决方案版本之间执行数据转换或升级。仅当目标 Dataverse 实例中已存在您要导入的解决方案,才调用此方法。

      该功能需要以下参数:

      参数 说明
      solutionName 解决方案的名称
      oldVersion 旧解决方案的名称
      newVersion 新解决方案的名称
      oldSolutionId 旧解决方案指南。
      newSolutionId 新解决方案指南。
    4. 在解决方案在 BeforeImportStage 方法的替代定义中完成导入前,输入要执行的自定义代码。 示例数据和在 ImportConfig.xml 文件中指定的解决方案的某些平面文件在解决方案导入完成之前导入。

    5. 使用 OverrideConfigurationDataFileLanguage 的替代方法定义替代配置数据导入当前选择的语言。 如果指定语言的指定区域设置 ID (LCID) 未在包中的可用语言列表中找到,则导入默认数据文件。

      ImportConfig.xml 文件的 <cmtdatafiles> 节点中的配置数据指定可用语言。 默认配置数据导入文件在 ImportConfig.xml 文件的 crmmigdataimportfile 属性中指定。

      跳过数据检查 (OverrideDataImportSafetyChecks = true) 此时可能有效,前提是您确定目标 Dataverse 实例不包含任何数据。

    6. AfterPrimaryImport> 方法的替代定义中完成导入后,输入要执行的自定义代码。 在解决方案开始导入之前,之前未导入的其余平面文件现在导入。

    7. 将包文件夹的默认名称更改为您想要的包名称。 为此,在解决方案资源管理器窗格中对 PkgFolder(或 PkgAssets)文件夹重命名,然后在 GetImportPackageDataFolderName 属性下编辑返回值。

      public override string GetImportPackageDataFolderName  
      {  
      get  
      {  
      // WARNING this value directly correlates to the folder name in the Solution Explorer where the ImportConfig.xml and sub content is located.  
      // Changing this name requires that you also change the correlating name in the Solution Explorer  
      return "PkgFolder";  
      }  
      }  
      
    8. 通过编辑 GetNameOfImport 属性下的返回值更改数据包名称。

      public override string GetNameOfImport(bool plural)  
      {  
      return "Package Short Name";  
      }  
      

      此返回值将在 Dynamics 365 Package Deployer 向导中的数据包选择页上显示的数据包的名称。

    9. 通过编辑 GetImportPackageDescriptionText 属性下的返回值更改数据包描述。

      
      public override string GetImportPackageDescriptionText  
      {  
      get { return "Package Description"; }  
      }  
      
      

      此返回值将在 Package Deployer 向导中的数据包选择页上的数据包名称上显示的数据包描述。

    10. 通过编辑 GetLongNameOfImport 属性下的返回值更改数据包长名称。

      
      public override string GetLongNameOfImport  
      {  
      get { return "Package Long Name"; }  
      }  
      
      

      在您选择了要安装的程序包之后,会在下一页上显示数据包长名称。

  3. 此外,数据包可以使用以下函数和变量:

    客户 类型​​ 说明
    CreateProgressItem(String) 函数 用于在用户界面中 (UI) 创建新的流程项目。
    RaiseUpdateEvent(String, ProgressPanelItemStatus) 函数 曾用于更新通过调用到 CreateProgressItem(String) 而创建的进度。

    ProgressPanelItemStatus 是采用以下值的枚举:

    正在处理 = 0
    完成 = 1
    失败 = 2
    警告 = 3
    未知 = 4
    RaiseFailEvent(String, Exception) Function 用于因异常消息而导致当前状态导入失败的情况。
    IsRoleAssoicatedWithTeam(Guid, Guid) 函数 用于确定角色是否与指定的团队相关联。
    IsWorkflowActive(Guid) 函数 用于确定指定的工作流是否可用。
    PackageLog 类指针 指向数据包的初始化登录界面的指针。 数据包利用此界面将消息和异常情况记录到包日志文件。
    RootControlDispatcher 属性 一个调度程序界面,用于在包部署期间允许控件呈现自己的 UI。 使用此界面可以整合所有 UI 元素或命令。 在使用此变量之前,很有必要为空值检查变量,因为不可将其设置为值。
    CrmSvc 属性 一个指向允许包在包内使用 Dynamics 365 的 CrmServiceClient 类的指针。 将此指针用于执行 SDK 方法以及替代方法中的其他操作。
    DataImportBypass 属性 指定 Dynamics 365 Package Deployer 是否跳过所有数据导入操作,如导入Dataverse 示例数据、平面文件数据,以及从配置迁移工具导出的数据。 指定 true 或 false。 默认值为 false
    OverrideDataImportSafetyChecks 属性 指定 Dynamics 365 Package Deployer 是否将绕过一些安全检查,这将帮助改进导入性能。 指定 truefalse。 默认值为 false

    仅当目标 Dataverse 实例不包含任何数据时,应将此属性设置为 true
  4. 保存项目。 下一步是构建包。

构建和部署

以下部分描述了如何生成和部署包。

内部版本号

根据您使用的工具,下面将介绍如何构建您的包。

要构建使用 CLI 创建的包,可以加载 .csproj 文件到 Visual Studio 中,但是我们将使用 dotnet 命令和 MSBuild。 下面的示例假定工作目录包含 *.csproj 文件。

> dotnet publish

DeploymentPackage -> C:\Users\peter\Downloads\DeploymentPackage\bin\Debug\DeploymentPackage.1.0.0.pdpkg.zip

您可以选择查看构建的包的详细信息。

> pac package show --package .\bin\Debug\DeploymentPackage.1.0.0.pdpkg.zip

您的包由 <Project>\Bin\Debug 文件夹下的以下文件组成。

  • <PackageName> 文件夹:文件夹名称与您在添加自定义代码一节的步骤 2.g 中为您的包文件夹名称更改的名称相同。 此文件夹包含所有解决方案、配置数据、平面文件和您的数据包的内容。

备注

您可能会看到一个包含 pdpublish 文件夹的 .NET 文件夹(例如,net472)。 您的 DLL 和其他项目文件位于这个 pdpublish 文件夹中。

  • <PackageName>.dll:程序集包含您的数据包的自定义代码。 默认情况下,程序集的名称与您的项目名称相同。

部署

在创建了包之后,您可以使用 Package Deployer 工具、Windows PowerShell 或 CLI 命令将其部署到 Dataverse 实例上。

  • 要使用 Package Deployer 工具进行部署,首先下载 Dataverse 开发工具中所述的工具。 接下来,按照文章使用 Package Deployer 或 Windows PowerShell 部署包中关于包部署的详细信息进行操作。

  • 要使用 CLI 进行部署,使用 pac package deploy 命令。

    > pac package deploy --package .\bin\Debug\DeploymentPackage.1.0.0.pdpkg.zip
    

    备注

    要使用 CLI 将包部署到目标环境,您必须首先设置身份验证配置文件并选择组织。 详细信息:pac auth createpac org select

最佳做法

下面列出了使用 Package Deployer 包时需要遵循的一些最佳做法提示。

创建包

创建包时,开发人员必须:

  • 确保已签署包程序集

部署包

部署包时,Dataverse 管理员必须:

  • 坚持使用已签名包的程序集,以便跟踪程序集回到其源。
  • 在生产实例上运行数据包之前,在预生产实例(最好是生产实例的镜像)上对其进行测试。
  • 在部署数据包之前对生产实例进行备份

另请参阅

解决方案包生成工具