教程:为组织将 Power BI 报表嵌入应用程序

本教程介绍了如何将 Power BI 报表嵌入到 .NET 5.0 应用程序中,这属于“为组织嵌入内容”(也称为“用户拥有数据”)解决方案的一部分。 在“为组织嵌入内容”解决方案中,应用用户需要使用自己的凭据对 Power BI 进行身份验证。

在本教程中,你将了解如何嵌入:

  • Power BI 报表
  • 在“为组织嵌入内容”应用中
  • 使用 .NET 5.0
  • 通过 Microsoft.Identity.Web 库(.NET Core 也支持此库)

注意

本教程中使用的完整解决方案可从 DOTNET5-UserOwnsData-Tutorial GitHub 存储库获取。

先决条件

资源

在本教程中,你使用:

方法

若要在“为组织嵌入内容”解决方案中嵌入 Power BI 内容,请执行以下步骤:

  1. 配置 Microsoft Entra 应用
  2. 获取嵌入的参数值
  3. 添加所需的 NuGet 包
  4. 启用服务器端身份验证
  5. 构建应用的客户端
  6. 运行应用程序

步骤 1 - 配置 Microsoft Entra 应用

当 Web 应用调用 Power BI 时,需要 Microsoft Entra 令牌才能调用 Power BI REST API 并嵌入 Power BI 项,例如报表、仪表板或磁贴。

如果没有 Microsoft Entra 应用,请按照注册 Microsoft Entra 应用程序以使用 Power BI 中的说明进行创建。

若要配置 Microsoft Entra 应用,请按照配置 Microsoft Entra 应用中的说明进行操作。

步骤 2 - 获取嵌入的参数值

若要嵌入报表,需要以下值:

域和租户 ID

如果不清楚自己的域或租户 ID,请参阅查找 Microsoft Entra 租户 ID 和主域名

注意

若要为其他租户上的用户嵌入内容(来宾用户),你需要调整 authorityUri 参数。

客户端 ID

若要获取客户端 ID GUID(也称为“应用程序 ID”),请执行以下步骤:

  1. 登录 Microsoft Azure

  2. 搜索“应用程序注册”,然后选择“应用程序注册”链接。

  3. 选择用于嵌入 Power BI 内容的 Microsoft Entra 应用。

  4. 从“概述”部分,复制“应用程序(客户端) ID”GUID 。

客户端机密

若要获取客户端机密,请执行下列步骤:

  1. 登录 Microsoft Azure

  2. 搜索“应用程序注册”,然后选择“应用程序注册”链接。

  3. 选择用于嵌入 Power BI 内容的 Microsoft Entra 应用。

  4. 在“管理”下,选择“证书和机密”

  5. 在“客户端机密”下,选择“新建客户端密钥” 。

  6. 在“添加客户端机密”弹出窗口中,提供应用程序机密的说明,选择应用程序机密过期时间,然后选择“添加” 。

  7. 从“客户端机密”部分,复制新创建的应用程序机密的“值”列中的字符串 。 客户端机密值为你的客户端 ID。

注意

请确保在第一次出现客户端密码值时复制它。 在你离开此页面后,客户端密码值将会隐藏起来,你将无法检索它。

工作区 ID

若要获取工作区 ID GUID,请执行以下步骤:

  1. 登录 Power BI 服务。

  2. 打开要嵌入的报表。

  3. 复制 URL 中的 GUID。 GUID 是 /groups/ 和 /reports/ 之间的数字 。

    A screenshot showing workspace ID GUID in the Power B I service U R L

注意

若要以编程方式获取工作区 ID,请使用获取组 API。

报表 ID

若要获取报表 ID GUID,请执行以下步骤:

  1. 登录 Power BI 服务。

  2. 打开要嵌入的报表。

  3. 复制 URL 中的 GUID。 GUID 是 /reports/ 和 /ReportSection 之间的数字 。

    A screenshot showing report ID GUID in the Power B I service U R L

注意

若要以编程方式获取报表 ID,请使用获取组中的报表 API。

步骤 3 - 添加所需的 NuGet 包

在开始之前,需要将 Microsoft.Identity.WebMicrosoft.PowerBI.Api NuGet 包添加到应用中。

将以下 NuGet 包添加到应用:

  • 在 VS Code 中,打开终端并键入以下代码

  • 在 Visual Studio 中,导航到“工具”>“NuGet 包管理器”>“包管理器控制台”,然后键入以下代码

dotnet add package Microsoft.Identity.Web -v 0.3.0-preview
dotnet add package Microsoft.Identity.Web.UI -v 0.3.0-preview
dotnet add package Microsoft.PowerBI.Api

如果应用曾使用 Microsoft.AspNetCore 进行身份验证,请键入以下内容,从项目中删除此包:

dotnet remove package Microsoft.AspNetCore.Authentication.AzureAD.UI

步骤 4 - 启用服务器端身份验证

通过创建或修改下表中的文件,在应用中启用服务器端身份验证。

文件 用途
Startup.cs 初始化 Microsoft.Identity.Web 身份验证服务
appsettings.json 身份验证详细信息
PowerBiServiceApi.cs 获取 Microsoft Entra 令牌和嵌入元数据
HomeController.cs 将嵌入数据作为模型传递到视图

配置启动文件以支持 Microsoft.Identity.Web

修改 Startup.cs 中的代码以正确初始化 Microsoft.Identity.Web 提供的身份验证服务。

将以下代码片段添加到应用的 Startup.cs 文件

注意

ConfigureServices 中的代码完成了几项重要任务:

  1. AddMicrosoftWebAppCallsWebApi 的调用配置 Microsoft 身份验证库,以获取访问令牌(Microsoft Entra 令牌)。
  2. AddInMemoryTokenCaches 的调用配置一个令牌缓存,Microsoft 身份验证库将使用该缓存在后台缓存访问令牌和刷新令牌
  3. services.AddScoped(typeof(PowerBiServiceApi)) 的调用将 PowerBiServiceApi 类配置为可使用依赖项注入添加到其他类的服务类。
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.TokenCacheProviders;
using Microsoft.Identity.Web.TokenCacheProviders.InMemory;
using Microsoft.Identity.Web.UI;
using UserOwnsData.Services;

namespace UserOwnsData {

  public class Startup {

    public Startup (IConfiguration configuration) {
      Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices (IServiceCollection services) {

      services
        .AddMicrosoftIdentityWebAppAuthentication(Configuration)
        .EnableTokenAcquisitionToCallDownstreamApi(PowerBiServiceApi.RequiredScopes)
        .AddInMemoryTokenCaches();

      services.AddScoped (typeof (PowerBiServiceApi));

      var mvcBuilder = services.AddControllersWithViews (options => {
        var policy = new AuthorizationPolicyBuilder()
          .RequireAuthenticatedUser()
          .Build();
        options.Filters.Add (new AuthorizeFilter (policy));
      });

      mvcBuilder.AddMicrosoftIdentityUI();

      services.AddRazorPages();

    }
  }
}

创建身份验证详细信息文件

在本教程中,appsettings.json 文件包含敏感信息,例如客户端 ID 和客户端机密 。 出于安全考虑,不建议在设置文件中保留此信息。 在应用程序中嵌入时,请考虑使用更安全的方法(如 Azure Key Vault)来保存此信息。

  1. 在项目中,创建一个新文件并将其命名为 appsettings.json。

  2. 然后将以下代码添加到 appsettings.json 中:

    {
        "AzureAd": {
            "Instance": "https://login.microsoftonline.com/",
            "Domain": "",
            "TenantId": "",
            "ClientId": "",
            "ClientSecret": "",
            "CallbackPath": "/signin-oidc",
            "SignedOutCallbackPath": "/signout-callback-oidc"
        },
        "PowerBi": {
            "ServiceRootUrl": "https://api.powerbi.com"
        },
        "Logging": {
            "LogLevel": {
                "Default": "Information",
                "Microsoft": "Warning",
                "Microsoft.Hosting.Lifetime": "Information"
            }
        },
        "AllowedHosts": "*"
    }
    
  3. 填写从步骤 2 - 获取嵌入参数值获取的嵌入参数值。

注意

在上面的代码片段中,将 PowerBi:ServiceRootUrl 参数作为自定义配置值添加,以跟踪 Power BI 服务的基 URL。 在对 Microsoft 公有云中的 Power BI 服务进行编程时,URL 为 https://api.powerbi.com/。 但是,Power BI 服务的根 URL 在其他云(例如政府云)中将有所不同。 因此,此值将存储为项目配置值,以便在需要时可轻松更改。

获取 Microsoft Entra 访问令牌,并调用 Power BI 服务

为了嵌入 Power BI 内容(例如报表和仪表板),应用需要获取 Microsoft Entra 令牌。 若要获取令牌,则需要一个配置对象

本部分中的代码使用 .NET Core 依赖项注入模式。 当你的类需要使用服务时,你可以为该服务添加构造函数参数,而 .NET Core 运行时负责在运行时传递服务实例。 在这种情况下,构造函数使用 IConfiguration 参数注入 .NET Core 配置服务的实例,该参数用于从 appsettings.json 中检索 PowerBi:ServiceRootUrl 配置值。 ITokenAcquisition 参数名为 tokenAcquisition,它包含对 Microsoft.Identity.Web 库提供的 Microsoft 身份验证服务的引用,用于从 Microsoft Entra ID 获取访问令牌。

RequiredScopes 字段包含一个字符串数组,该数组包含由 Power BI 服务 API 支持的一组委托权限。 当应用程序通过网络调用以获取 Microsoft Entra 令牌时,该应用程序将传递这组委托权限,以便 Microsoft Entra ID 可以将其包含在其返回的访问令牌中。

注意

验证是否已使用 Web 应用所需的范围配置 Microsoft Entra 应用。 有关详细信息,请参阅更改 Microsoft Entra 应用的权限

  1. 在应用的项目中,创建名为“服务”的新文件夹。

  2. 在“服务”文件夹中,创建名为“PowerBiServiceApi.cs”的新文件 。

  3. 将以下代码添加到 PowerBiServiceApi.cs 中。

    using Microsoft.Identity.Web;
    using Microsoft.PowerBI.Api;
    using Microsoft.PowerBI.Api.Models;
    using Microsoft.Rest;
    using Newtonsoft.Json;
    
    namespace UserOwnsData.Services {
    
      // A view model class to pass the data needed to embed a single report.
      public class EmbeddedReportViewModel {
         public string Id;
         public string Name;
         public string EmbedUrl;
         public string Token;
      }
    
    public class PowerBiServiceApi {
         private ITokenAcquisition tokenAcquisition { get; }
         private string urlPowerBiServiceApiRoot { get; }
    
         public PowerBiServiceApi(IConfiguration configuration, ITokenAcquisition tokenAcquisition) {
             this.urlPowerBiServiceApiRoot = configuration["PowerBi:ServiceRootUrl"];
             this.tokenAcquisition = tokenAcquisition;
         }
    
         public static readonly string[] RequiredScopes = new string[] {
             "https://analysis.windows.net/powerbi/api/Report.Read.All"
         };
    
        // A method to get the Azure AD token (also known as 'access token')
         public string GetAccessToken() {
             return this.tokenAcquisition.GetAccessTokenForUserAsync(RequiredScopes).Result;
         }
    
         public PowerBIClient GetPowerBiClient() {
             var tokenCredentials = new TokenCredentials(GetAccessToken(), "Bearer");
             return new PowerBIClient(new Uri(urlPowerBiServiceApiRoot), tokenCredentials);
         }
    
         public async Task<EmbeddedReportViewModel> GetReport(Guid WorkspaceId, Guid ReportId) {
             PowerBIClient pbiClient = GetPowerBiClient();
             // Call the Power BI Service API to get embedding data
       var report = await pbiClient.Reports.GetReportInGroupAsync(WorkspaceId, ReportId);
    
       // Return report embedding data to caller
       return new EmbeddedReportViewModel {
        Id = report.Id.ToString(),
        EmbedUrl = report.EmbedUrl,
        Name = report.Name,
        Token = GetAccessToken()
       };
      }
    
     }
    
    }
    

修改 HomeController.cs 文件

在此代码示例中,将使用依赖项注入。 通过在 ConfigureServices 方法中调用 services.AddScoped,将 PowerBiServiceApi 类注册为服务时。 可以向构造函数添加 PowerBiServiceApi 参数,.NET Core 运行时负责创建 PowerBiServiceApi 实例并将其传递给构造函数。

在“Controllers”文件夹中,打开 HomeController.cs 文件,并将其添加到以下代码段:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using UserOwnsData.Models;
using UserOwnsData.Services;

namespace UserOwnsData.Controllers {
    [Authorize]
    public class HomeController : Controller {

        private PowerBiServiceApi powerBiServiceApi;

        public HomeController (PowerBiServiceApi powerBiServiceApi) {
            this.powerBiServiceApi = powerBiServiceApi;
        }

        [AllowAnonymous]
        public IActionResult Index() {
            return View();
        }

        public async Task<IActionResult> Embed() {
            Guid workspaceId = new Guid("11111111-1111-1111-1111-111111111111");
            Guid reportId = new Guid("22222222-2222-2222-2222-222222222222");
            var viewModel = await powerBiServiceApi.GetReport(workspaceId, reportId);
            return View(viewModel);
        }

        [AllowAnonymous]
        [ResponseCache (Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public IActionResult Error() {
            return View (new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
        }
    }
}

步骤 5 - 构建应用的客户端

对于客户端实现,需要创建或修改下表中的文件。

文件 用途
embed.js 包含客户端 JavaScript 代码
Embed.cshtml 包含应用的文档对象模型 (DOM),以及用于嵌入报表的 DIV

为嵌入式报表创建容器

创建 Embed.cshtml 文件,该文件包含一个 div 元素(用作嵌入式报表的容器)和三个脚本。

  1. 在“视图”>“主页”文件夹中,创建名为 Embed.cshtml 的文件 。

  2. 将以下代码片段添加到 Embed.cshtml 文件。

    @model UserOwnsData.Services.EmbeddedReportViewModel;
    
    <div id="embed-container" style="height:800px;"></div>
    
    @section Scripts {
    
        <!-- powerbi.min.js is the JavaScript file that loads the client-side Power BI JavaScript API library.
        Make sure that you're working with the latest library version.
        You can check the latest library available in https://cdnjs.com/libraries/powerbi-client -->
        <script src="https://cdn.jsdelivr.net/npm/powerbi-client@2.21.0/dist/powerbi.min.js"></script>
    
        <!-- This script creates a JavaScript object named viewModel which is accessible to the JavaScript code in embed.js. -->
        <script> 
            var viewModel = {
                reportId: "@Model.Id",
                embedUrl: "@Model.EmbedUrl",
                token: "@Model.Token"
            }; 
        </script>
    
        <!-- This script specifies the location of the embed.js file -->
        <script src="~/js/embed.js"></script>
    }
    

添加客户端 JavaScript 以嵌入报表

若要嵌入 Power BI 内容,需要创建一个配置对象。 若要详细了解如何创建配置对象,请参阅嵌入报表

在本部分,你将使用变量 models 来创建名为 embed.js 的 JavaScript 文件,其中带有一个配置对象,用于嵌入报表

使用对 window['powerbi-client'].models 的调用初始化 modelsmodels 变量用于设置配置值,如 models.Permissions.Allmodels.TokenType.Aadmodels.ViewMode.View

powerbi.embed 函数使用 models 配置对象嵌入报表。

  1. 在“wwwroot”>“js”文件夹中,创建名为 embed.js 的文件 。

  2. 将以下代码片段添加到 embed.js 文件。

    $(function(){
        // 1 - Get DOM object for div that is report container
        let reportContainer = document.getElementById("embed-container");
    
        // 2 - Get report embedding data from view model
        let reportId = window.viewModel.reportId;
        let embedUrl = window.viewModel.embedUrl;
        let token = window.viewModel.token
    
        // 3 - Embed report using the Power BI JavaScript API.
        let models = window['powerbi-client'].models;
        let config = {
            type: 'report',
            id: reportId,
            embedUrl: embedUrl,
            accessToken: token,
            permissions: models.Permissions.All,
            tokenType: models.TokenType.Aad,
            viewMode: models.ViewMode.View,
            settings: {
                panes: {
                    filters: { expanded: false, visible: true },
                    pageNavigation: { visible: false }
                }
            }
        };
    
        // Embed the report and display it within the div container.
        let report = powerbi.embed(reportContainer, config);
    
        // 4 - Add logic to resize embed container on window resize event
        let heightBuffer = 12;
        let newHeight = $(window).height() - ($("header").height() + heightBuffer);
        $("#embed-container").height(newHeight);
        $(window).resize(function() {
            var newHeight = $(window).height() - ($("header").height() + heightBuffer);
            $("#embed-container").height(newHeight);
        });
    
    });
    

步骤 6 - 运行应用程序

完成了本教程中列出的所有调整后,便可以运行应用程序。 执行应用程序并试验 Power BI 报表的嵌入方式。 可以使用 Power BI 嵌入式分析客户端 API 来通过客户端 API 增强你的应用。

应用准备就绪后,可以将嵌入式应用移动到生产环境