You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Blazor项目中嵌入并切换显示多个PowerBI报表

解决方案:Blazor嵌入PowerBI多报表动态切换

核心思路

通过让API接收报表标识参数,动态读取appsettings.json中对应报表的配置,配合Blazor页面传递不同参数,实现不同页面加载不同报表的效果,无需新增控制器。


步骤1:优化配置结构(可选但更规范)

修改appsettings.json,将多报表配置统一归类,便于管理:

{
  "AzureAppInfo": {
    "AuthenticationMode": "ServicePrincipal",
    "AuthorityUri": "https://login.microsoftonline.com/TenantId",
    "ClientId": "d7177345-fa2e-4ef5-9d42-619441aa18f0",
    "TenantId": "32e5e8eb-b522-4d94-b35f-75e6755a9b83",
    "Scope": "https://analysis.windows.net/powerbi/api/.default",
    "ClientSecret": "V3d8Q~s3TyFB3aKHxkEsf36UsU2ngP8O~K.UEbcP"
  },
  "PowerBIReports": {
    "Default": {
      "WorkspaceId": "08ec7b7f-8b1a-4952-8f9c-c8d65e8d7ab3",
      "ReportId": "e3ceb447-0ae6-4398-a14d-abf16fe11031"
    },
    "Test": {
      "WorkspaceId": "08ec7b7f-8b1a-4952-8f9c-c8d65e8d7ab3",
      "ReportId": "ac1d04be-9d9c-47b7-bcda-fb225ac00ce1"
    }
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

如果不想修改现有配置结构,可直接跳到步骤2,通过条件判断读取原有的PowerBI和ReportTest节点。


步骤2:修改PowerBIController,支持动态参数

2.1 添加配置模型类

创建对应配置的实体类,用于绑定配置:

public class PowerBIReportConfig
{
    public string WorkspaceId { get; set; }
    public string ReportId { get; set; }
}

2.2 绑定配置(Program.cs/Startup.cs)

在服务注册中绑定多报表配置:

// Program.cs
builder.Services.Configure<Dictionary<string, PowerBIReportConfig>>(
    builder.Configuration.GetSection("PowerBIReports")
);

2.3 修改API接口,接收报表标识

更新控制器方法,根据传入的reportKey动态获取对应报表配置:

[ApiController]
[Route("api/[controller]")]
public class PowerBIController : ControllerBase
{
    private readonly IOptions<Dictionary<string, PowerBIReportConfig>> _reportConfigs;
    private readonly IConfiguration _configuration;

    public PowerBIController(IOptions<Dictionary<string, PowerBIReportConfig>> reportConfigs, IConfiguration configuration)
    {
        _reportConfigs = reportConfigs;
        _configuration = configuration;
    }

    [HttpGet("{reportKey}")]
    public async Task<IActionResult> Get(string reportKey)
    {
        // 校验报表标识是否存在
        if (!_reportConfigs.Value.TryGetValue(reportKey, out var reportConfig))
        {
            return BadRequest("无效的报表标识");
        }

        // 原有认证逻辑不变
        var scopes = new[] { _configuration["AzureAppInfo:Scope"] };
        var app = ConfidentialClientApplicationBuilder
            .Create(_configuration["AzureAppInfo:ClientId"])
            .WithClientSecret(_configuration["AzureAppInfo:ClientSecret"])
            .WithAuthority(new Uri(_configuration["AzureAppInfo:AuthorityUri"]))
            .Build();

        var authResult = await app.AcquireTokenForClient(scopes).ExecuteAsync();
        var tokenCredentials = new TokenCredentials(authResult.AccessToken, "Bearer");
        var pbiClient = new PowerBIClient(new Uri("https://api.powerbi.com/"), tokenCredentials);

        // 使用动态获取的配置加载报表
        var workspaceId = new Guid(reportConfig.WorkspaceId);
        var reportId = new Guid(reportConfig.ReportId);
        var report = pbiClient.Reports.GetReportInGroup(workspaceId, reportId);

        var tokenRequest = new GenerateTokenRequest(TokenAccessLevel.View, report.DatasetId);
        var embedTokenResponse = await pbiClient.Reports.GenerateTokenAsync(workspaceId, reportId, tokenRequest);

        var reportViewModel = new EmbeddedReportViewModel(
            report.Id.ToString(),
            report.Name,
            report.EmbedUrl,
            embedTokenResponse.Token);

        return Ok(reportViewModel);
    }

    // 保持原有EmbeddedReportViewModel定义
    public class EmbeddedReportViewModel
    {
        public string Id { get; set; }
        public string Name { get; set; }
        public string EmbedUrl { get; set; }
        public string Token { get; set; }

        public EmbeddedReportViewModel(string id, string name, string embedUrl, string token)
        {
            Id = id;
            Name = name;
            EmbedUrl = embedUrl;
            Token = token;
        }
    }
}

如果保留原有appsettings.json结构,可替换控制器中的配置读取逻辑为:

[HttpGet("{reportType}")]
public async Task<IActionResult> Get(string reportType)
{
    string workspaceIdStr, reportIdStr;

    switch(reportType)
    {
        case "Default":
            workspaceIdStr = _configuration["PowerBI:WorkspaceId"];
            reportIdStr = _configuration["PowerBI:ReportId"];
            break;
        case "Test":
            workspaceIdStr = _configuration["ReportTest:WorkspaceId"];
            reportIdStr = _configuration["ReportTest:ReportId"];
            break;
        default:
            return BadRequest("无效的报表类型");
    }

    // 后续认证、报表加载逻辑不变...
}

步骤3:修改Blazor页面,传递报表标识

方案A:单组件多路由(推荐)

将PowerBIReport.razor改为可接收路由参数的组件,不同路由传递不同标识:

@page "/powerbi/{reportKey}"
@inject HttpClient Http

<div @ref="PowerBIElement" class="powerbi-container"></div>
@if (!string.IsNullOrEmpty(errorMessage))
{
    <p class="text-danger">@errorMessage</p>
}

@code {
    [Parameter]
    public string ReportKey { get; set; } = "Default";

    private IJSObjectReference? embedModule;
    private ElementReference PowerBIElement;
    private PowerBIController.EmbeddedReportViewModel? reportViewModel;
    private string errorMessage = string.Empty;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            var embedModuleTask = JS.InvokeAsync<IJSObjectReference>("import", "./scripts/powerbi-embed.js");
            var reportViewModelTask = Http.GetFromJsonAsync<PowerBIController.EmbeddedReportViewModel>($"api/PowerBI/{ReportKey}");
            
            embedModule = await embedModuleTask;
            reportViewModel = await reportViewModelTask;
            StateHasChanged();
        }
        else if (embedModule is not null && reportViewModel is not null)
        {
            errorMessage = string.Empty;
            await embedModule.InvokeVoidAsync("embedReport",
                PowerBIElement,
                reportViewModel.Id,
                reportViewModel.EmbedUrl,
                reportViewModel.Token);
        }
    }
}

使用时通过不同路由访问:

  • /powerbi/Default:加载默认报表
  • /powerbi/Test:加载测试报表

方案B:独立页面调用

如果是两个独立的Blazor页面,直接在各自页面中指定不同的报表标识:

@page "/report-default"
@inject HttpClient Http

<!-- 页面内容 -->
@code {
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            var embedModuleTask = JS.InvokeAsync<IJSObjectReference>("import", "./scripts/powerbi-embed.js");
            var reportViewModelTask = Http.GetFromJsonAsync<PowerBIController.EmbeddedReportViewModel>("api/PowerBI/Default");
            
            // 后续嵌入逻辑同PowerBIReport.razor
        }
    }
}
@page "/report-test"
@inject HttpClient Http

<!-- 页面内容 -->
@code {
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            var embedModuleTask = JS.InvokeAsync<IJSObjectReference>("import", "./scripts/powerbi-embed.js");
            var reportViewModelTask = Http.GetFromJsonAsync<PowerBIController.EmbeddedReportViewModel>("api/PowerBI/Test");
            
            // 后续嵌入逻辑同PowerBIReport.razor
        }
    }
}

内容的提问来源于stack exchange,提问作者William Sewell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 22:10:29