使用Power Automate上传附件到Dynamics 365集成的SharePoint

发布时间 2023-07-17 17:45:59作者: 不为人知的鹅妈妈

  在Dynamics 365中使用SharePoint集成做实体的附件管理,这里不像用Annotation实体存放附件可以直接用代码直接创建Annotation记录,如果想要对外部提供接口把附件上传到SharePoint,我们可以使用Power Automate中的SharePoint组件来生成文件,通过HTTP流供给外部系统调用。

 

 

下面是Power Automate的完整步骤

 

1.当收到HTTP请求时

method:POST

请求正文JSON架构:

{
    "type": "object",
    "properties": {
        "contractId": {
            "type": "string"
        },
        "fileList": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "fileName": {
                        "type": "string"
                    },
                    "fileBase64": {
                        "type": "string"
                    }
                },
                "required": [
                    "fileName",
                    "fileBase64"
                ]
            }
        }
    }
}

请求JSON示例:

{
  "contractId": "09101368-65EA-ED11-8848-002248EE98C7",
  "fileList": [
    {
      "fileName": "newpic.png",
      "fileBase64": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAOCAYAAAAbvf3sAAAAAXNSR0IArs4c6QAArkJggg=="
    },
    {
      "fileName": "测试文档V1.2.docx",
      "fileBase64": "UEsDBBQAAAAIAIdO4kCiCB42aAEAAHoCAAAQAAAAZG9jUHJvcHMvYXBwLnht..."
    }
  ]
}
contractId为D365中关联附件的实体id,用于获取实体的附件目录等信息,fileList为文件列表,接口可一次上传多个文件,fileBase64为文件的Base64字符串。
 

2.初始化result变量

添加一个初始化变量的操作,result为变量名,类型为对象,这个对象用来作为http请求的返回结果。

 3.分析文件列表JSON

添加一个“数据操作”,选择“分析JSON”,内容选择入参里的fileList

 4.获取合同记录

选择Dataverse里的按ID获取行操作,根据入参的contractId获取合同的相关信息。

 5.获取id路径

这里初始化了一个字符串变量IdPath,用来存放附件的文档目录,后面的步骤会用,到下面的“值”可以不用管。

6.获取合同文档位置

 添加一个Dataverse操作,用来获取当前合同记录的文档位置,表名称选择“文档位置”。

 Fetch Xml查询的内容如下:

<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
  <entity name="sharepointdocumentlocation">
    <attribute name="name" />
    <attribute name="regardingobjectid" />
    <attribute name="parentsiteorlocation" />
    <attribute name="relativeurl" />
    <attribute name="absoluteurl" />
    <order attribute="name" descending="false" />
    <filter type="and">
      <condition attribute="locationtype" operator="eq" value="0" />
      <condition attribute="servicetype" operator="eq" value="0" />
    </filter>
    <link-entity name="new_contract" from="new_contractid" to="regardingobjectid" link-type="inner" alias="ae">
      <filter type="and">
        <condition attribute="new_contractid" operator="eq" value="@{outputs('获取合同记录')?['body/new_contractid']}" />
      </filter>
    </link-entity>
  </entity>
</fetch>

需要注意:单纯只创建一条合同记录,CRM后台是不会生成和它关联的sharepointdocumentlocation记录,在CRM窗体上打开“附件”选项卡后,后台就能查到sharepointdocumentlocation记录了,所以我们可以通过自动查询SharePoint文档的方式来触发生成sharepointdocumentlocation记录。我这里的在合同创建的后的自定义插件里执行对sharepointdocument的fetchxml查询,这样合同只要创建了,就会默认生成文档位置记录。

 7.遍历文档位置

添加一个变量操作,将上一步查询到的文档位置的“相对URL”字段赋值给IdPath变量,第6步返回的是一个结果集,所以指定赋值结果后,操作会“遍历每一个”包含起来,实际上只会有一条记录返回。

 8.初始化变量

初始化3个变量,FileFullName、FileName、FielExtension用来存放文件的文件名、不带后缀的文件名、文件后缀名。

9.遍历fileList

 将入参里的fileList“应用到每一个”,循环逐条创建文件。

 10.设置文件后缀名、文件名(无后缀)

通过文件名中的“.”分割获取文件的名称和后缀,表达式分别为last(split(items('应用到每一个')['fileName'],'.'))、replace(items('应用到每一个')['FileName'], variables('FielExtension'), '')

 11.获取文件夹是否存在

如果当前合同没有上传过附件,那么文档目录在SharePoint对应的路径是不存在的,需要先判断文件夹是否存在。这里使用SharePoint的“将HTTP请求发送到SharePoint”操作。站点地址选择存放文档的SharePoint站点,方法选择GET,Uri为_api/web/GetFolderByServerRelativeUrl('/new_contract/@{variables('IdPath')}')/Exists。Uri中的new_contract为合同实体的逻辑名,如果是其他实体就换成对应实体的逻辑名称,返回的结果为true或false。

 

 12.判断文件夹是否存在

表达式左侧为 body('获取文件夹是否存在')?['d']?['Exists']

13.获取文件(仅属性)

在“如果是”的分支,添加SharePoint操作“获取文件(仅属性)”,筛选查询添加文件名筛选条件FileLeafRef eq '@{items('应用到每一个')['fileName']}',结果会返回文件夹内符合文件名的文件属性。

 

14.检查文件名是否存在

 添加分支操作,表达式左侧为 empty(outputs('获取文件(仅属性)')?['body/value']),右侧为true,如果不存在,则可以正常按文件名上传,如果文件名已经存在,则直接上传会出现重名错误,这时需要将文件更名或者删除已有文件,这里我选择将文件名后面增加一个时间后缀,避免文件重复。

15.创建文件

选择SharePoint的创建文件操作,站点地址为SharePoint的地址,文件夹路径为new_contract/@{variables('IdPath')},文件名为FileFullName变量,文件内容需要通过base64表达式进行转换,这里的表达式为:base64ToBinary(items('应用到每一个')['fileBase64'])

 在第12步的“如果不是”分支,直接按原文件名创建就行。

16.响应

 将result变量作为响应的正文返回,这里result的内容没有做处理,如果有需要也可以对result结果进行自定义处理。