自定义连接器开发常见问题解答

下面是开发自定义 Power Query 连接器时可能会出现的常见问题的一些解答。

常规

如果...,是否可以显示警告?

在记录的警告模式之外,我们目前不提供返回带外警告(例如大型表或大型元数据警告)的方法。

是否可以通过向导航层次结构添加另一个级别来显示表分区信息,并允许用户选择一个或多个分区?

如果最终用户经常想要检索单个数据分区,则有可能。 但是,无法将此功能添加到已有的连接器中。 本质上,此更改会中断已存在的连接器。

故障排除

我开发的自定义连接器在 Power BI Desktop 中工作正常。 但是,当我尝试在 Power BI 服务中运行它时,我无法设置凭据或配置数据源。 为什么会这样?

你看到此行为的原因可能有多种。 在 Power BI 服务上运行连接器时可能会出现的一些常见错误如下:

  • 无法更新数据源凭据
  • 尝试从 DataSourceReference 中获取 OAuthProvider 时发生异常
  • 不支持给定的数据源类型

在开始解决此问题之前,请首先收集自定义连接器的副本(.pq 或 .mez 文件)。 如果你有 .mez 文件,请将此文件重命名为 .zip 并提取 .pq 文件。

若要对自定义连接器进行故障排除,请执行以下操作:

  1. 在所选文本编辑器中打开自定义连接器文件 (.pq)。

  2. 找到 TestConnection 函数。 TestConnection 函数对于 Power BI 服务中的计划刷新是必需的,但不在 Power BI Desktop 中使用。 检查用于 TestConnection 实现的 .pq 文件,并确认参数是否与连接器的数据源函数匹配。 详细信息:处理网关支持

  3. 如果连接器使用 OAuth,请检查 state 参数。 仅服务故障的常见原因是连接器的 StartLogin 实现中缺少 state 参数。 此参数不在 Power BI Desktop 中使用,但在 Power BI 服务中是必需的。 state 参数必须传递到 Uri.BuildQueryString 调用中。 下面的示例演示 state 的正确实现。

StartLogin = (resourceUrl, state, display) =>
  let
      authorizeUrl = authorize_uri & "?" & Uri.BuildQueryString([
          response_type = "code",
          client_id = client_id,
          state = state,                 //correct implementation
          redirect_uri = redirect_uri,
          resource = resource
      ])
  in
      [
          LoginUri = authorizeUrl,
          CallbackUri = redirect_uri,
          WindowHeight = 720,
          WindowWidth = 1024,
          Context = null
      ];

在 Power Query 导航器中打开架构或数据库时,会立即开始提取数据库中的所有表,而不是等待选择表。 导致此行为的原因是什么?

此行为可能是生成导航表的方式的副作用。 如果你要使用 Table.TransformRows 创建新记录,则此用法通常会导致对数据表进行预先评估。 但是,Table.AddColumn 生成的值是延迟生成的。 因此,在以下示例代码中,除非用户查询实际引用此数据,否则不会计算“每个 GetSchemas(url, [用户])”。

GetShares = (server_host as text) as table =>
    let
        url =  server_host & "/shares",
        shares = GetItems(url),
        withData = Table.AddColumn(shares, "Data", each GetSchemas(url, [name])),
        withItemKind = Table.AddColumn(withData, "ItemKind", each "Folder"),
        withItemName = Table.AddColumn(withItemKind, "ItemName", each "Folder"),
        withIsLeaf = Table.AddColumn(withItemName, "IsLeaf", each false),
        renamed = Table.RenameColumns(withIsLeaf, {{"name", "Name"}, {"key", "Key"}}),
        navTable = Table.ToNavigationTable(renamed, {"Key"}, "Name", "Data", "ItemKind", "ItemName", "IsLeaf")
    in
        navTable;

单个表可能包含多个分区文件。 当前实现会先下载所有文件,然后再显示预览。 在有足够的行可供预览之前有没有办法避免下载所有文件而只下载部分文件?

此行为是使用 Table.Combine 的副作用。 另一种方法是生成“表的表”并使用 Table.ExpandTableColumn 函数。 此方法可根据需要延迟扩展分区。 例如:

GetFiles = (tables_url as text, table_name as text) as table =>
    let
        // parse raw ndjson and get the list of parquet files
        // resp format: line 1: protocol, line 2: schema, line 3..:file info
        resp = Lines.FromBinary(SendRequest(tables_url & "/" & table_name & "/query", [
            Headers= [#"Content-Type"="application/json"],
            Content= Text.ToBinary("{}")
        ]), null, null, 1252),
        protocol = resp{0}, // TODO: Add protocol version check
        schema = Json.Document(Json.Document(resp{1})[metaData][schemaString])[fields],
        columnNames = List.Transform(schema, each [name]),

        fileInfos = List.Range(resp, 2),
        fileUrls = List.Transform(fileInfos, each Json.Document(_)[file][url]),
        numFiles = List.Count(fileUrls),

        toTable = Table.FromList(fileUrls, Splitter.SplitByNothing(), {"FileUrl"}),
        processPartition = Table.AddColumn(toTable, "Data", each Parquet.Document(Binary.Buffer(ProtectSensitiveQueryParameters([FileUrl], [ManualCredentials = true])))),
        removeFileUrl = Table.RemoveColumns(processPartition, {"FileUrl"}),
        expanded = Table.ExpandTableColumn(removeFileUrl, "Data", columnNames)
    in
        if numFiles = 0 then #table(columnNames, {}) else expanded;

ProtectSensitiveQueryParameters = (url as text, options as record) =>
    let
        uriParts = Uri.Parts(uri),
        uriWithoutQuery = Uri.FromParts(uriParts & [Query = []]),
        modifiedOptions = options & [
            CredentialQuery = uriParts[Query],
        ]
    in
        Web.Contents(uriWithoutQuery, modifiedOptions);

其他信息

注意

开发自定义连接器的问题超出了 Microsoft 支持范围,需要专业知识。 如果需要帮助开发自定义连接器,或者有任何反馈、建议或 bug 需要报告,请访问 GitHub 上的官方公共存储库,或者如果有兴趣联系推荐的第三方自定义连接器开发人员顾问,请联系 Microsoft 联系人。