Power Apps ポータルで Azure Functions 経由で Dataverse に アクセスしてエンティティ レコードのプライマリ画像を表示する

Power Apps ポータルで、ページ上に Dataverse に格納されているエンティティ レコードのデータを表示する際、 fetchxml テンプレート タグを使用して、 Dataverse へのクエリ結果を取得する方法をよく使います。  
まれに、この fetchxml では取得できないエンティティの属性があります。例えば「プライマリ画像」属性です。
例えば、私が Dataverse 上で勝手に作った「物件 」というエンティティの、あるレコードを モデル駆動型アプリ のフォームで表示している以下の画面キャプチャの、マンションの画像が「プライマリ画像」です。
![PrimaryImageOnPowerApps.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455051/53d9e4b0-9cbf-dcaf-2c7c-54b45e2730c7.png)

今回は、Azure Functions を活用してその fetchxml の課題を解決するアプローチをとって、その画像を Power Apps ポータル上で表示することにトライします。

# 目的
以下のような Power Apps ポータル ページを実装する。

- Dataverse に格納されていエンティティレコードの ID を受け取り、プライマリ画像を取得して、BASE64 画像データとして返す Azure Functions アプリを開発する
- ポータル ページ上で、その Azure Functions アプリを呼び出して画像データを受け取り、その画像を表示する

# 開発手順
### ① Azure Functions アプリの開発
今回利用する Azure Functions アプリは、以下の記事で紹介しているものと同一です。後に、そちらで開発した Azure Functions アプリを呼び出します。BASE64 画像データを受け取ります。

- [Azure Functions 3.x で .NET 5.0 を使って Dataverse に格納されているレコードを取得する](https://qiita.com/keijiinoue/items/e8f66b4ea2abb77ed160 "Azure Functions 3.x で .NET 5.0 を使って Dataverse に格納されているレコードを取得する")

さらに今回は、Power Apps ポータル ページ上で動作する JavaScript から上記 Azure Functions アプリを呼び出します。ですので、 CORS の設定をします。以下のように、対象となる Power Apps ポータルの URL を入力します。
![CORS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455051/60f7a5a6-5163-9710-7479-b1272bf2e2df.png)

### ② Power Apps ポータルでの実装
##### 1. 物件の画像を表示するためのプレースホルダの追加
物件の画像を表示したい Web ページに関連付けられている Web テンプレート上に、物件の画像を表示するためのプレースホルダとなる &lt;img&gt; 要素を追加します。

```html:Web&#x20;テンプレートの一部
<img id="KeijiPropertyImage" data-propertyid="{{ propertyid }}" src="PropertyImagePlaceholder.png" style="max-width: 144px; max-height: 144px;">
```

要素に指定した文字列は、以下のような意味を持ちます。

| 要素の文字列 | 意味 | 準備 |
|:-:|:-:|:-:|
| {{ propertyid }}  |  Dataverse に格納されている物件エンティティ レコードの ID |  Liquid の assign タグを使うなどして、 Web テンプレート内で propertyid に適切な ID 文字列を設定しておきます。 |
| PropertyImagePlaceholder.png  |  実際の物件の画像が取得され表示される前に既定で表示するダミーの画像 | これ専用の画像ファイルを作成し、対象の Web ページの子 Web ファイルとして登録しておきます。  |

私は PropertyImagePlaceholder.png として以下のようなものを用意しました。
![PropertyImagePlaceholderCaptured.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455051/785fa4b0-f8cb-2194-80b4-5e01bd10b331.png)

##### 2. Azure Funcions アプリの関数の呼び出しと画像の差し替え
対象の Web ページ の JavaScript に、以下のコードを追加します。

```javascript:Web&#x20;ページの&#x20;JavaScript&#x20;の一部
let propertyid = $("#KeijiPropertyImage").data("propertyid");
$.post(
  "https://keiji-function-app-xxxxxxxxxxxx.azurewebsites.net/api/httptrigger1?code=xxxxxxxxxxxxxxxxxxxxxxxxx",
  JSON.stringify({
    entityName: "keiji_property",
    recordId: propertyid,
    imageAttributeName: "keiji_primaryimage",
  }),
  function (data) {
    $("#KeijiPropertyImage").attr("src", data);
  },
  "text"
);
```

Power Apps ポータル ページ上では jQuery の \$ が利用できます。$.post() で Azure Functions アプリの関数を呼び出す URL を指定し、適宜パラメーターを渡して画像データを取得します。  
非同期での画像データ取得後に、既存の &lt;img&gt; の src 属性を更新することで、Power Apps ポータル ページ上に取得した画像が表示されます。
![RetrievedPropertyImageCaptured.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455051/d11ea050-c761-f256-197b-67af0fc37d15.png)

以上で目的が達成できました。

# その他の方法の考察
プライマリ画像で使用したのと同じ画像ファイルを、Power Apps ポータルの Web ファイル として適切な ID 付きのファイル名で保存しておく、というアプローチも有効です。この場合、Web テンプレートで動的に、相応しい ID 付きのファイル名 Web ファイルを &lt;img&gt; の src 属性 で指定することなど、 Power Apps ポータルにプライマリ画像を表示することも可能です。  

ただし、この方法の場合には、画像ファイルをモデル駆動型アプリでも登録し、Power Apps ポータル側でも登録する、という 2 か所での登録が必要となります。  

また、こちらの方法にもメリットがあります。フルサイズの画像を利用することができる点です。今回の記事で参照している Azure Functions アプリの実装では、エンティティ レコードのプライマリ画像として、フルサイズの画像を取得する方法を見つけられず、サムネイル画像の取得のみできています。その理由は、今回参照している Azure Functions アプリ は最新の .NET 5.0 の利用にフォーカスしたためと考えます。従来からの .NET Framework 4.x を利用したものであれば Azure Functions 1.x を利用して、フルサイズの画像を取得する Dataverse の Web API を内部的に呼び出して取得することが可能と考えるためです。