将 Power BI 报表导出到文件

使用 exportToFile API,可通过 REST 调用来导出 Power BI 报表。 支持以下文件格式:

  • .pptx (PowerPoint)
  • .pdf
  • .png
    • 导出为 .png 时,包含多个报表页的报表会压缩为 .zip 文件
    • .zip 中的每个文件都代表一个报表页
    • 报表页名称与 Get PagesGet Pages in Group API 返回的值相同

注意

Premium Per User (PPU) 不支持使用 exportToFile API 将 Power BI 报表导出到文件。

用法示例

可通过多种方式使用导出功能。 下面是几个示例:

  • “发送到打印程序”按钮 - 在应用中创建一个按钮;如果有人单击此按钮,就会触发导出作业。 此作业可将已查看的报表导出为 .pdf 或 .pptx。 完成后,用户可以下载该文件。 使用书签,可以导出处于特定状态(包括应用配置的筛选器、切片器和其他设置)的报表。 由于此 API 是异步的,因此可能需要一段时间才能获取文件。

  • 电子邮件附件 - 每隔一段时间自动发送包含 .pdf 报表附件的电子邮件。 如果需要自动向主管发送每周报表,就会发现此方案非常有用。 有关更多信息,请参阅使用 Power Automate 导出 Power BI 报表并以电子邮件的方式发送

使用 API

许可要求

  • 要导出的报表必须位于由 Premium、Embedded 或 Fabric 容量支持的工作区中。
  • Premium Per User (PPU) 支持 exportToFile API。

管理员设置

使用此 API 前,请先验证是否已启用以下管理员租户设置

  • 将报表导出为 PowerPoint 演示文稿或 PDF 文档 - 默认处于启用状态。
  • 将报表导出为图像文件 - 只有导出为 .png 才需要启用,默认处于禁用状态。

“呈现”事件

若要确保在视觉对象完成呈现后才开始导出,请使用“呈现”事件 API,并且仅在呈现完成后才开始导出。

轮询

此 API 是异步的。 调用后,exportToFile API 会触发导出作业。 在导出作业触发后,使用轮询来跟踪此作业,直到它完成。

在轮询期间,此 API 返回表示已完成工作量的数字。 每个导出作业中的工作量都是根据作业中的导出总数计算的。 导出包括导出单个视觉对象或导出带有或不带有书签的页面。 所有导出的权重都相同。 例如,如果导出作业包含导出 10 页的报表,且轮询返回了 70,则表示此 API 处理了导出作业里 10 页中的 7 页。

在导出完成后,轮询 API 调用返回用于获取文件的 Power BI URL。 此 URL 在 24 小时内有效。

支持的功能

本部分介绍如何使用以下受支持功能:

选择要打印哪些报表页

根据 Get PagesGet Pages in Group 返回值,指定要打印的报表页。 还可以指定要导出的报表页的顺序。

导出页面或单个视觉对象

可以指定要导出的页面或单个视觉对象。 可以导出带有或不带有书签的页面。

需要根据导出的类型将不同的属性传递给 ExportReportPage 对象。 下表指定了每个导出作业需要的属性。

注意

导出单个视觉对象与导出页面(带有或不带有书签)的权重相同。 这意味着就系统计算而言,两个操作都具有相同的值。

Attribute 单个视觉对象 注释
bookmark 可选 不适用于: 用于导出处于特定状态的页面
pageName 适用于。 适用于 使用 GetPages REST API 或 getPages 客户端 API
visualName 不适用于: 适用于。 可通过两种方法获取视觉对象的名称:
  • 使用 getVisuals 客户端 API
  • 侦听并记录 visualClicked 事件,此事件在选择视觉对象时触发。 有关详细信息,请参阅如何处理事件
  • 书签

    书签可用于在特定的配置中保存报表,包括已应用的筛选器和报表视觉对象的状态。 可以通过两种方式使用 exportToFile API 以编程方式导出报表的书签:

    • 导出现有书签

      若要导出现有报表书签,请使用 name 属性,它是一个唯一(区分大小写)标识符,你可以使用书签 JavaScript API 获取该标识符。

    • 导出报表的状态

      若要导出报表的当前状态,请使用 state 属性。 例如,可以使用书签的 bookmarksManager.capture 方法来捕获特定用户对报表所做的更改,然后使用 capturedBookmark.state 导出当前状态下的报表。

    注意

    不支持导出使用个人书签永久性筛选器的报表。

    筛选器

    使用 PowerBIReportExportConfiguration 中的 reportLevelFilters,可以在筛选条件下导出报表。

    若要导出筛选报表,请将要用作筛选器的 URL 查询字符串参数插入到 ExportFilter。 输入字符串时,必须删除 URL 查询参数的 ?filter= 部分。

    该表包含一些可传递给 ExportFilter 的字符串的语法示例。

    筛选器 语法 示例
    字段中的一个值 Table/Field eq 'value' Store/Territory eq 'NC'
    字段中的多个值 Table/Field in ('value1', 'value2') Store/Territory in ('NC', 'TN')
    一个字段中的非重复值,另一个字段中的其他非重复值 Table/Field1 eq 'value1' and Table/Field2 eq 'value2' Store/Territory eq 'NC' and Store/Chain eq 'Fashions Direct'

    身份验证

    只能使用用户(或主用户)或服务主体进行身份验证。

    行级别安全性 (RLS)

    使用行级别安全性 (RLS),可以导出仅对特定用户显示数据的报表。 例如,若要导出使用区域角色定义的销售报表,可以编程方式对该报表进行筛选,使其只显示特定区域。

    若要使用 RLS 导出报表,必须拥有以下权限:

    • 报表连接到的语义模型的写入权限
    • 报表所在的工作区的参与者或管理员

    数据保护

    .pdf 和 .pptx 格式支持敏感度标签。 如果将包含敏感度标签的报表导出为 .pdf 或 .pptx,导出的文件会显示包含其敏感度标签的报表。

    无法使用服务主体将具有敏感度标签的报表导出到 .pdf 或 .pptx。

    本地化

    使用 exportToFile API 时,可以传递所需区域设置。 本地化设置会影响报表的显示方式(例如,根据所选的本地化设置来更改格式设置)。

    动态绑定

    若要在报表连接到非默认语义模型时导出报表,请在调用 API 时在 datasetToBind 参数中指定所需的语义模型 ID。 详细了解动态绑定

    并发请求

    exportToFile API 支持有限数量的并发请求。 支持的最大并发请求数是每个容量 500 个。 若要避免超出限制并收到 请求过多 (429) 错误,请随时间推移或跨容量分配负载。 只会同时处理一个报表中的 5 页。 例如,如果要导出一个 50 页的报表,导出作业将按 10 个顺序间隔进行处理。 优化导出作业时,可能会希望并行执行多个作业。

    代码示例

    创建导出作业时,要遵循以下四个步骤:

    1. 发送导出请求
    2. 轮询
    3. 获取文件
    4. 使用文件流

    此部分举例说明了各个步骤。

    第 1 步 - 发送导出请求

    第 1 步是发送导出请求。 在下面的示例中,导出请求是针对特定报表页发送的。

    private async Task<string> PostExportRequest(
        Guid reportId,
        Guid groupId,
        FileFormat format,
        IList<string> pageNames = null, /* Get the page names from the GetPages REST API */
        string urlFilter = null)
    {
        var powerBIReportExportConfiguration = new PowerBIReportExportConfiguration
        {
            Settings = new ExportReportSettings
            {
                Locale = "en-us",
            },
            // Note that page names differ from the page display names
            // To get the page names use the GetPages REST API
            Pages = pageNames?.Select(pn => new ExportReportPage(Name = pn)).ToList(),
            // ReportLevelFilters collection needs to be instantiated explicitly
            ReportLevelFilters = !string.IsNullOrEmpty(urlFilter) ? new List<ExportFilter>() { new ExportFilter(urlFilter) } : null,
    
        };
    
        var exportRequest = new ExportReportRequest
        {
            Format = format,
            PowerBIReportConfiguration = powerBIReportExportConfiguration,
        };
    
        // The 'Client' object is an instance of the Power BI .NET SDK
        var export = await Client.Reports.ExportToFileInGroupAsync(groupId, reportId, exportRequest);
    
        // Save the export ID, you'll need it for polling and getting the exported file
        return export.Id;
    }
    

    第 2 步 - 轮询

    发送导出请求后,请使用轮询来确定等待的导出文件何时准备就绪。

    private async Task<HttpOperationResponse<Export>> PollExportRequest(
        Guid reportId,
        Guid groupId,
        string exportId /* Get from the PostExportRequest response */,
        int timeOutInMinutes,
        CancellationToken token)
    {
        HttpOperationResponse<Export> httpMessage = null;
        Export exportStatus = null;
        DateTime startTime = DateTime.UtcNow;
        const int c_secToMillisec = 1000;
        do
        {
            if (DateTime.UtcNow.Subtract(startTime).TotalMinutes > timeOutInMinutes || token.IsCancellationRequested)
            {
                // Error handling for timeout and cancellations 
                return null;
            }
    
            // The 'Client' object is an instance of the Power BI .NET SDK
            httpMessage = await Client.Reports.GetExportToFileStatusInGroupWithHttpMessagesAsync(groupId, reportId, exportId);
            exportStatus = httpMessage.Body;
    
            // You can track the export progress using the PercentComplete that's part of the response
            SomeTextBox.Text = string.Format("{0} (Percent Complete : {1}%)", exportStatus.Status.ToString(), exportStatus.PercentComplete);
            if (exportStatus.Status == ExportState.Running || exportStatus.Status == ExportState.NotStarted)
            {
                // The recommended waiting time between polling requests can be found in the RetryAfter header
                // Note that this header is not always populated
                var retryAfter = httpMessage.Response.Headers.RetryAfter;
                var retryAfterInSec = retryAfter.Delta.Value.Seconds;
                await Task.Delay(retryAfterInSec * c_secToMillisec);
            }
        }
        // While not in a terminal state, keep polling
        while (exportStatus.Status != ExportState.Succeeded && exportStatus.Status != ExportState.Failed);
    
        return httpMessage;
    }
    

    第 3 步 - 获取文件

    在轮询返回 URL 后,参照下面的示例来获取收到的文件。

    private async Task<ExportedFile> GetExportedFile(
        Guid reportId,
        Guid groupId,
        Export export /* Get from the PollExportRequest response */)
    {
        if (export.Status == ExportState.Succeeded)
        {
            // The 'Client' object is an instance of the Power BI .NET SDK
            var fileStream = await Client.Reports.GetFileOfExportToFileAsync(groupId, reportId, export.Id);
            return new ExportedFile
            {
                FileStream = fileStream,
                FileSuffix = export.ResourceFileExtension,
            };
        }
        return null;
    }
    
    public class ExportedFile
    {
        public Stream FileStream;
        public string FileSuffix;
    }
    

    步骤 4 - 使用文件流

    如果有文件流,可以按照最适合你需要的方式对其进行处理。 例如,你可以通过电子邮件发送它或使用它来下载导出的报表。

    端到端示例

    这是导出报表的端到端示例。 此示例包括以下几个阶段:

    1. 发送导出请求
    2. 轮询
    3. 获取文件
    private async Task<ExportedFile> ExportPowerBIReport(
    	Guid reportId,
    	Guid groupId,
    	FileFormat format,
    	int pollingtimeOutInMinutes,
    	CancellationToken token,
    	IList<string> pageNames = null,  /* Get the page names from the GetPages REST API */
        string urlFilter = null)
    {
    	const int c_maxNumberOfRetries = 3; /* Can be set to any desired number */
    	const int c_secToMillisec = 1000;
    	try
    	{
    		Export export = null;
    		int retryAttempt = 1;
    		do
    		{
    			var exportId = await PostExportRequest(reportId, groupId, format, pageNames, urlFilter);
    			var httpMessage = await PollExportRequest(reportId, groupId, exportId, pollingtimeOutInMinutes, token);
    			export = httpMessage.Body;
    			if (export == null)
    			{
    				// Error, failure in exporting the report
    				return null;
    			}
    			if (export.Status == ExportState.Failed)
    			{
    				// Some failure cases indicate that the system is currently busy. The entire export operation can be retried after a certain delay
    				// In such cases the recommended waiting time before retrying the entire export operation can be found in the RetryAfter header
    				var retryAfter = httpMessage.Response.Headers.RetryAfter;
    				if(retryAfter == null)
    				{
    				    // Failed state with no RetryAfter header indicates that the export failed permanently
    				    return null;
                    }
    
                    var retryAfterInSec = retryAfter.Delta.Value.Seconds;
                    await Task.Delay(retryAfterInSec * c_secToMillisec);
                }
            }
            while (export.Status != ExportState.Succeeded && retryAttempt++ < c_maxNumberOfRetries);
    
            if (export.Status != ExportState.Succeeded)
            {
                // Error, failure in exporting the report
                return null;
            }
    
            var exportedFile = await GetExportedFile(reportId, groupId, export);
    
            // Now you have the exported file stream ready to be used according to your specific needs
            // For example, saving the file can be done as follows:
            /*
                var pathOnDisk = @"C:\temp\" + export.ReportName + exportedFile.FileSuffix;
    
                using (var fileStream = File.Create(pathOnDisk))
                {
                    exportedFile.FileStream.CopyTo(fileStream);
                }
            */
    
            return exportedFile;
        }
        catch
        {
            // Error handling
            throw;
        }
    }
    

    注意事项和限制

    • 导出 API 操作负载将被评估为运行缓慢的后台操作,如高级容量负载评估中所述。
    • 要导出的报表中的所有相关语义模型必须驻留在高级容量或嵌入式容量中,包括具有直接查询连接的语义模型。
    • 导出的报表的文件大小不得超过 250MB。
    • 导出为 .png 时,不支持敏感度标签。
    • 单个导出的报表中可包含的导出(单个视觉对象或报表页面)的数量为 50(这不包括导出分页报表)。 如果请求包含更多导出,此 API 会返回错误,导出作业也会遭取消。
    • Power BI 的“将报表导出到文件”功能不支持个人书签永久性筛选器
    • 如果使用时没有书签或 reportLevelFilters,则 exportToFile API 将使用默认值导出报表。
    • 不支持导出连接到至少一个启用了单一登录(SSO)的外部数据源的一个或多个复合语义模型的 Power BI 报表。 导出时,视觉对象可能无法正确呈现。
    • 使用 REST API 导出具有动态绑定的报表时,动态绑定语义模型不能是具有对 SQL Server Analysis Services(SSAS)的直接查询的复合模型exportToFile
    • 此处列出的 Power BI 视觉对象不受支持。 导出包含这些视觉对象的报表时,包含这些视觉对象的报表部分不会呈现,并将显示错误符号。
      • 未经认证的 Power BI 自定义视觉对象
      • R 视觉对象
      • PowerApps
      • Python 视觉对象
      • Power Automate
      • 分页报表视觉对象
      • Visio
      • ArcGIS 视觉对象

    了解如何为客户和组织嵌入内容:

    有更多疑问? 尝试参与 Power BI 社区