チュートリアル: DAX クエリの実行 REST API を使用して.NET中間層サービスを構築する

このチュートリアルでは、Microsoft.Samples.XMLA.ExecuteQueries サンプル、つまり ADOMD.NET を使用して XMLA エンドポイントを介して DAX クエリをプロキシする .NET Web API を取り上げ、これを Execute DAX Queries REST API を使うように変更します。この変更により、結果が Apache Arrow IPC 形式で返されます。 このサンプルでは、中間層フレームワーク (ルーティング、レート制限、正常性プローブ) を提供します。 このチュートリアルでは、XMLA/ADOMD クエリ実行プラミングを REST API 呼び出しと方向 IPC 応答処理に置き換える方法について説明します。

[前提条件]

  • .NET 8 SDK 以降。
  • 少なくとも 1 つのセマンティック モデルを持つ Premium またはFabric容量のPower BI ワークスペース。
  • クライアント シークレットを使用したMicrosoft Entra アプリの登録。
  • サービス プリンシパルは、ワークスペース メンバーとして共同作成者(またはそれ以上)のロールで追加されました。
  • 次のテナント設定が有効になっています。
    • データセット実行クエリ REST API および サービス プリンシパルが Power BI API を使用 (開発者設定)。
    • オンプレミスのセマンティック モデルで XMLA エンドポイントと Excelでの分析を許可 (統合設定)。

サンプル サービス アーキテクチャの詳細については、sample README を参照してください。

始める前の準備

サンプル サービスでは、ADOMD.NET で XMLA エンドポイントを使用します。 このチュートリアルでは、DAX クエリの実行 REST API を使用するように変換します。これにより、結果が Apache Arrow IPC 形式で返されます。 どちらの方法でも、Power BIセマンティック モデルに対して DAX クエリを実行できますが、重要な方法は異なります。

XMLA/ADOMD.NET DAX クエリの実行 REST API
プロトコル HTTPS 経由の XMLA (独自のバイナリ) Standard REST (HTTP POST/response)
クライアント ライブラリ Microsoft.AnalysisServices.AdomdClient — Windows指向 (.NET Core パッケージは使用可能ですが、クロスプラットフォーム サポートは制限されています)、セッションと接続を管理します HttpClient + Apache.Arrow — 軽量、クロスプラットフォーム、ステートレス
認証 アクセス トークンを含む接続文字列。接続レベルのセッション リクエストごとのベアラートークンで、セッション状態なし
応答の形式 ADOMD クライアント ライブラリによって解析された表形式の行セット Apache Arrow IPC — 広範なエコシステムサポート (Python、R、Spark、DuckDB) を備えた列形式バイナリ形式
接続管理 セッションセットアップコストを分散するためにプールが必要 ステートレス HTTP — プーリングは必要ありません。MSAL がトークン キャッシュを処理する
最適な用途 従来の統合、MDX クエリ、きめ細かなセッション制御 よりシンプルな HTTP 統合、列形式のパフォーマンス、または言語間コンシューマーが必要な新しいサービス

新しいサービスを構築するとき、またはダウンストリーム コンシューマーが Arrow IPC (分析パイプライン、Python ノートブック、列形式データベースなど) の恩恵を受けることができる場合は、>Execute DAX Queries REST APIXMLA/ADOMD を保持します。

1 - サンプルを複製して確認する

リポジトリを複製し、コンパイルを確認します。

git clone https://github.com/dbrownems/Microsoft.Samples.XMLA.ExecuteQueries.git
cd Microsoft.Samples.XMLA.ExecuteQueries
dotnet build

このソリューションには、中間層サービス (Microsoft.Samples.XMLA.ExecuteQueries) とロード テスト クライアント (Tester) の 2 つのプロジェクトが含まれています。 ライブ ワークスペースに対して元のサービスを実行する必要はありません。変更を行う前に、ビルドが成功したことを確認するだけです。

2 - NuGet の依存関係を更新する

Microsoft.Samples.XMLA.ExecuteQueries プロジェクトで、ADOMD.NET パッケージを削除し、Arrow API のパッケージを追加します。

cd Microsoft.Samples.XMLA.ExecuteQueries
dotnet remove package Microsoft.AnalysisServices.AdomdClient.NetCore.retail.amd64
dotnet add package Apache.Arrow
dotnet add package Microsoft.Identity.Client

要求/応答モデルの種類を再利用する場合は、Microsoft.PowerBI.Api パッケージを保持します。それ以外の場合は削除し、独自の DTO を定義します。

3 - ADOMD 接続プールを MSAL トークン キャッシュに置き換える

このサンプルでは、AdomdConnectionPool.cs を使用して XMLA 接続をプールします。 Arrow API はステートレス REST エンドポイントであるため、接続プールを MSAL トークン キャッシュに置き換えます。

新しい TokenService.cs ファイルを作成します。

using Microsoft.Identity.Client;

public class TokenService
{
    private readonly IConfidentialClientApplication _app;
    private readonly string[] _scopes =
        { "https://analysis.windows.net/powerbi/api/.default" };

    public TokenService(IConfiguration config)
    {
        _app = ConfidentialClientApplicationBuilder
            .Create(config["PowerBI:ClientId"])
            .WithClientSecret(config["PowerBI:ClientSecret"])
            .WithAuthority(AzureCloudInstance.AzurePublic,
                config["PowerBI:TenantId"])
            .Build();
    }

    public async Task<string> GetAccessTokenAsync()
    {
        var result = await _app
            .AcquireTokenForClient(_scopes).ExecuteAsync();
        return result.AccessToken;
    }
}

MSAL はトークンを自動的にキャッシュします。後続の呼び出しでは、有効期限が切れるまでキャッシュされたトークンが返されます。

AdomdConnectionPool.csAdomdExtensions.csを削除します。 これらは不要です。

4 - クエリ ハンドラーを更新して Arrow API を呼び出す

Handlers.csで、ADOMD クエリの実行を、DAX クエリの実行エンドポイントへの HTTP 呼び出しに置き換えます。

すべての ADOMD 参照 (AdomdConnectionPoolAdomdConnectionAdomdCommandWrappedConnection) を削除します。 接続プールとワークスペースの参照ではなく、ハンドラーの挿入された依存関係を TokenServiceHttpClient に変更します。

ルート パラメーターで既に使用可能なワークスペースとデータセット GUID から REST API URL を構築します。

var url = $"https://api.powerbi.com/v1.0/myorg/groups/{workspaceId}"
        + $"/datasets/{datasetId}/executeDaxQueries";

JSON 要求本文を使用して DAX クエリを POST します。

var token = await tokenService.GetAccessTokenAsync();

using var request = new HttpRequestMessage(HttpMethod.Post, url);
request.Headers.Authorization =
    new AuthenticationHeaderValue("Bearer", token);
request.Content = new StringContent(
    JsonSerializer.Serialize(new { query, queryTimeout = 120 }),
    Encoding.UTF8, "application/json");

var response = await httpClient.SendAsync(
    request, HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();

HttpCompletionOption.ResponseHeadersReadを使用して、バッファリングなしで応答本文がストリームされるようにします。これは、大規模な結果セットにとって重要です。

5 - 矢印 IPC 応答を処理する

DAX クエリの実行 API は、応答本文で連結された 1 つ以上の方向 IPC ストリームを返します。 各ストリームには、その目的を示すスキーマ メタデータが含まれています。

  • データの結果 — クエリ結果 (特別なメタデータ フラグなし)。
  • エラー結果IsError=trueはスキーマメタデータ内にあり、FaultCode値とFaultString値を使用しています。
  • 実行メトリックIsExecMetrics=true ( executionMetrics パラメーターを使用してメトリックを要求した場合)。

DataResult.csを、矢印応答を処理するロジックに置き換えます。 中間層が単に Arrow IPC をダウンストリーム コンシューマーに転送する場合は、逆シリアル化せずにバイトをストリーミングします。

context.Response.ContentType = "application/vnd.apache.arrow.stream";
await response.Content.CopyToAsync(context.Response.Body);

結果を検査したり、形式を変換したりする必要がある場合は、 ArrowStreamReaderを使用して方向ストリームを逆シリアル化します。

using var stream = await response.Content.ReadAsStreamAsync();
using var reader = new ArrowStreamReader(stream);

while (true)
{
    var batch = await reader.ReadNextRecordBatchAsync();
    if (batch == null) break;
    // Process batch — convert to JSON, filter rows, etc.
}

エラー応答を検出するには、スキーマ メタデータを確認します。

var metadata = reader.Schema.Metadata;
if (metadata.TryGetValue("IsError", out var isError)
    && isError == "true")
{
    var faultCode = metadata.GetValueOrDefault(
        "FaultCode", "Unknown");
    var faultString = metadata.GetValueOrDefault(
        "FaultString", "Unknown error");
    // Return error to caller
}

6 - ワークスペースの構成を簡略化する

サンプルの appsettings.json では、ADOMD がカタログ名で接続するため、XMLA エンドポイントとデータセット名の参照が構成されます。 Arrow REST API では、要求 URL から直接ワークスペースとデータセット GUID が使用されるため、構成が簡単になります。

サービス プリンシパルの資格情報で appsettings.json を更新し、XMLA 固有のフィールドを削除します。

{
  "PowerBI": {
    "TenantId": "YOUR_TENANT_ID",
    "ClientId": "YOUR_APP_CLIENT_ID",
    "ClientSecret": "YOUR_CLIENT_SECRET"
  }
}

Workspaces配列とXmlaEndpoint配列を含む Datasets セクションは不要です。 Workspace.csDataset.csを削除したり、ガバナンスの許可リストとしてDatasetsリストを再利用したりできます (サービスがクエリできるデータセットを制限します)。

7 - サービスを登録し、ルーティングを更新する

Program.csで、ADOMD プールとワークスペースの登録を新しいサービスに置き換えます。

builder.Services.AddSingleton<TokenService>();
builder.Services.AddHttpClient();

DAX クエリの実行エンドポイント パターンに一致するようにルートを更新します。

app.MapPost(
    "/v1.0/myorg/groups/{workspaceId:Guid}"
    + "/datasets/{datasetId:Guid}/executeDaxQueries",
    Handlers.ExecuteDaxQueriesInGroup);

サンプルに含まれる既存のレートリミッター、正常性プローブ、そしてリクエストカウンターは、現状のままで引き続き役立ちます。

8 - サービスをテストする

サービスを実行します。

dotnet run --project Microsoft.Samples.XMLA.ExecuteQueries

別のターミナルから、DAX クエリを送信します。

curl -X POST https://localhost:3000/v1.0/myorg/groups/YOUR_WORKSPACE_ID/datasets/YOUR_DATASET_ID/executeDaxQueries \
  -H "Content-Type: application/json" \
  -d '{"query": "EVALUATE TOPN(5, '\''DimProduct'\'')"}'

応答はバイナリの Arrow IPC ストリームです。 ファイルに保存し、Pythonで検査します。

curl -s -o result.arrow https://localhost:3000/v1.0/myorg/groups/YOUR_WORKSPACE_ID/datasets/YOUR_DATASET_ID/executeDaxQueries \
  -H "Content-Type: application/json" \
  -d '{"query": "EVALUATE TOPN(5, '\''DimProduct'\'')"}'

python -c "
import pyarrow as pa
reader = pa.ipc.open_stream('result.arrow')
table = reader.read_all()
print(table.schema)
print(table.to_pandas())
"

変更の概要

元のファイル アクション
AdomdConnectionPool.cs Delete — MSAL トークン キャッシュによって置き換えられます TokenService.cs
AdomdExtensions.cs 削除 - JSON ストリーミング ロジックが不要になった
DataResult.cs 書き換え — Arrow IPCをストリーム配信するか、ArrowStreamReaderでデシリアライズする
Handlers.cs 書き換え — ADOMD 実行の代わりに DAX クエリ API を実行するための HTTP POST
Workspace.cs / Dataset.cs 簡略化または削除 - REST API では、カタログ名ではなく GUID が使用されます
Program.cs 更新TokenServiceIHttpClientFactoryの登録; ルートの更新
appsettings.json 簡略化 — サービス プリンシパルの資格情報のみ。XMLA 構成の削除
.csproj Update — ADOMD パッケージを削除します。Apache.ArrowMicrosoft.Identity.Client を追加します。

リソースをクリーンアップする

テストが完了したら、次の手順を実行します。

  1. ローカル サービスを停止します (ターミナルで Ctrl キーを押しながら C キーを押します)。
  2. このチュートリアル専用のMicrosoft Entra アプリ登録を作成した場合は、Azure ポータルに移動して削除します。
  3. 不要になった場合は、Power BI ワークスペースからサービス プリンシパルを削除します。