Tutorial: Constrói um serviço .NET de nível intermédio com a API REST Execute DAX Queries

Neste tutorial, utiliza-se o exemplo Microsoft.Samples.XMLA.ExecuteQueries — uma API Web .NET que serve como proxy para as consultas DAX através do endpoint XMLA, usando ADOMD.NET — e modifica-se para usar a API REST Execute DAX Queries, que devolve os resultados no formato Apache Arrow IPC. A amostra fornece a estrutura de nível intermédio (roteamento, limitação de velocidade, sonda de saúde). Este tutorial mostra-lhe como substituir a canalização de execução de consultas XMLA/ADOMD por chamadas de API REST e gestão de respostas Arrow IPC.

Pré-requisitos

  • .NET 8 SDK ou posterior.
  • Um espaço de trabalho Power BI em capacidade Premium ou Fabric com pelo menos um modelo semântico.
  • Um registo de aplicação do Microsoft Entra com um segredo de cliente.
  • O principal de serviço foi adicionado como membro do espaço de trabalho com um papel de Contribuinte (ou superior).
  • As seguintes configurações de inquilino estão ativadas:
    • Dataset Execute Queries REST API e Permite que as entidades de serviço usem APIs do Power BI (em Definições de programador).
    • Permitir endpoints XMLA e Analisar em Excel com modelos semânticos locais (em Configurações de integração).

Para detalhes sobre a arquitetura de serviço de exemplo, consulte o exemplo README.

Antes de começar

O serviço de exemplo utiliza o endpoint XMLA com ADOMD.NET. Este tutorial converte-o para usar a API REST Execute DAX Queries, que devolve resultados no formato Apache Arrow IPC. Ambas as abordagens permitem executar consultas DAX contra modelos semânticos do Power BI, mas diferem em aspetos importantes.

XMLA / ADOMD.NET API REST de Execução de Consultas DAX
Protocol XMLA via HTTPS (binário proprietário) REST Padrão (HTTP POST / resposta)
Biblioteca de cliente Microsoft.AnalysisServices.AdomdClient — orientado para Windows (pacote .NET Core disponível mas suporte limitado multiplataforma), gere sessões e ligações HttpClient + Apache.Arrow — leve, multiplataforma, sem estado
Authentication String de conexão com token de acesso; Sessão ao nível de conexão Token de portador por pedido; Sem estado de sessão
Formato de resposta Conjuntos de linhas tabulares analisados pela biblioteca cliente ADOMD Apache Arrow IPC — um formato binário colunar com amplo suporte a ecossistemas (Python, R, Spark, DuckDB)
Gestão de ligações Exige agrupamento para amortizar o custo de configuração da sessão HTTP sem estado — não é necessário pooling; O MSAL gere a cache de tokens
Melhor para Integrações legadas, consultas MDX, controlo de sessão detalhado Novos serviços onde pretende uma integração HTTP mais simples, desempenho colunar ou consumidores multilinguagem

Escolha a API REST Execute Consultas DAX quando estiver a construir um novo serviço ou quando os seus consumidores a jusante podem beneficiar do IPC Arrow (por exemplo, pipelines de análise, Python notebooks ou bases de dados colunares). Mantém o XMLA/ADOMD se precisares de suporte MDX ou confia em funcionalidades ao nível da sessão, como membros calculados para uma sessão.

1 - Clonar e verificar a amostra

Clone o repositório e confirme que compila:

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

A solução contém dois projetos: o serviço de nível intermédio (Microsoft.Samples.XMLA.ExecuteQueries) e um cliente de teste de carga (Tester). Não precisa de correr o serviço original num ambiente de trabalho em tempo real — basta verificar se a construção tem sucesso antes de fazer alterações.

2 - Atualizar dependências do NuGet

No projeto Microsoft.Samples.XMLA.ExecuteQueries, remova o pacote ADOMD.NET e adicione pacotes para a API Arrow:

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

Mantém o pacote Microsoft.PowerBI.Api se quiseres reutilizar os seus tipos de modelo de pedido/resposta; caso contrário, remova-o e defina os seus próprios DTOs.

3 - Substituir o agrupamento de conexões ADOMD pelo cache de tokens MSAL

Este exemplo utiliza AdomdConnectionPool.cs para reunir ligações XMLA. A API Arrow é um endpoint REST sem estado, por isso substitui o pool de ligações pelo cache de tokens MSAL.

Criar um novo ficheiro 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;
    }
}

O MSAL armazena em cache os tokens automaticamente — as chamadas subsequentes retornam o token em cache até este expirar.

Apagar AdomdConnectionPool.cs e AdomdExtensions.cs. Já não são necessários.

4 - Atualizar o gestor de consultas para chamar a API Arrow

Em Handlers.cs, substitua a execução da consulta ADOMD por uma chamada HTTP ao endpoint Executar Consultas DAX.

Remover todas as referências ADOMD (AdomdConnectionPool, AdomdConnection, AdomdCommand, WrappedConnection). Mude as dependências injetadas do handler para TokenService e HttpClient em vez de pools de conexões e consultas de espaço de trabalho.

Constrói o URL da API REST a partir dos GUIDs do workspace e dos datasets já disponíveis nos parâmetros de rota.

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

Envie a consulta DAX com um corpo de pedido JSON:

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();

Use HttpCompletionOption.ResponseHeadersRead para que o corpo da resposta seja transmitido sem buffer — isto é particularmente importante para grandes conjuntos de resultados.

5 - Gerir a resposta IPC do Arrow

A API Execute DAX Queries devolve um ou mais fluxos Arrow IPC concatenados no corpo da resposta. Cada fluxo inclui metadados do esquema que indicam o seu propósito:

  • Resultado dos dados — os resultados da consulta (sem flags especiais de metadados).
  • Resultado de erro — nos metadados do esquema, com valores FaultCode e FaultString.
  • Métricas de execuçãoIsExecMetrics=true (se pedir métricas através do executionMetrics parâmetro).

Substitui DataResult.cs por lógica que gere a resposta do Arrow. Se a sua empresa de gama média simplesmente encaminha o IPC Arrow para os consumidores a jusante, transmita os bytes sem desserialização:

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

Se precisar de inspecionar resultados ou converter formatos, desserialize o fluxo Arrow com 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.
}

Verifique os metadados do esquema para detetar respostas de erro:

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 - Simplificar a configuração do espaço de trabalho

A amostra appsettings.json configura os endpoints XMLA e as pesquisas de nomes de conjuntos de dados porque o ADOMD se liga por nome de catálogo. A API Arrow REST utiliza GUIDs de workspace e de conjunto de dados diretamente da URL do pedido, pelo que a configuração é mais simples.

Atualize appsettings.json com as suas credenciais de principal de serviço e remova os campos específicos do XMLA:

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

A Workspaces secção com XmlaEndpoint e Datasets arrays já não é necessária. Pode eliminar Workspace.cs e Dataset.cs, ou reutilizar a Datasets lista como lista de permissões para governação (restringindo que conjuntos de dados o serviço pode consultar).

7 - Registar serviços e atualizar encaminhamento

Em Program.cs, substitua o pool ADOMD e os registos de espaços de trabalho pelos novos serviços:

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

Atualize a rota para corresponder ao padrão endpoint Execute DAX Queries:

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

O limitador de taxa existente, a sonda de integridade e o contador de pedidos do exemplo continuam a ser úteis tal como estão.

8 - Testar o serviço

Execute o serviço:

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

A partir de outro terminal, envie uma consulta 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'\'')"}'

A resposta é um fluxo binário do protocolo Arrow IPC. Guarde num ficheiro e inspecione com 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())
"

Resumo das alterações

Ficheiro original Ação
AdomdConnectionPool.cs Delete — substituído por cache de tokens MSAL em TokenService.cs
AdomdExtensions.cs Eliminar — Lógica de streaming JSON já não é necessária
DataResult.cs Reescrever — transmitir Arrow IPC em fluxo contínuo, ou desserializar utilizando ArrowStreamReader
Handlers.cs Reescrita — HTTP POST para executar API de consultas DAX em vez de execução ADOMD
Workspace.cs / Dataset.cs Simplificar ou eliminar — a API REST usa GUIDs, não nomes de catálogo
Program.cs Atualização — registar TokenService e IHttpClientFactoryatualizar rota ;
appsettings.json Simplificar — apenas credenciais de principal de serviço; remover configuração XMLA
.csproj Update — remover o pacote ADOMD; adiciona Apache.Arrow e Microsoft.Identity.Client

Limpeza de recursos

Quando terminares os testes:

  1. Pare o serviço local (pressione Ctrl+C no terminal).
  2. Se tiveres criado um registo de aplicativo do Microsoft Entra apenas para este tutorial, navega até ao portal Azure e elimina-o.
  3. Remova o principal de serviço do workspace do Power BI se já não for necessário.