Power BI Embedded 中的多租户
Multi-tenancy in Power BI Embedded
我有一个多租户 Web 应用程序,我正在使用每个租户一个数据库的方法。 Web 应用程序还将使用 Power BI Embedded 来显示基于特定租户数据的报告,每个租户的所有报告都将具有相同的格式,但数据源将不同。
据我所知,在 Power BI 中实现多租户并没有直接的方法,例如将数据源作为参数传递。我设法找到了两种使 Power BI 嵌入式多租户的方法。要么使用行级安全性,这意味着我需要为所有租户的数据提供一个单一的数据仓库,这对我来说不是一个选择。另一种选择是每个租户有一个工作空间。
对于第二个选项,我将有一个模板工作区,将从中为每个新租户创建一个副本。本教程介绍了如何操作:https://powerbi.microsoft.com/fr-fr/blog/duplicate-workspaces-using-the-power-bi-rest-apis-a-step-by-step-tutorial/ .
能否通过 Power BI C# SDK 完成同样的事情?我还需要更改每个工作区使用的数据源。我如何才能对我工作区中的所有报告执行此操作?
最后,有人发现了一种更简单的方法来实现嵌入 Power BI 的多租户吗?
这取决于您的数据源类型(SQL服务器、SSAS、CSV 文件等)和数据连接模式(导入、直接查询等)。如果您可以使用参数,那么您的选择之一是允许新克隆的报告使用 connection specific parameters 切换其数据源本身。为此,单击 Edit Queries
打开 Power Query Editor
,然后在 Manage Parameters
中定义两个新的文本参数,让我们将它们命名为 ServerName
和 DatabaseName
:
将它们的当前值设置为指向您的数据源之一,例如SQLSERVER2016
和 AdventureWorks2016
。然后在报告中右键单击您的查询并打开 Advanced Editor
。在M代码中找到服务器名和数据库名:
并将它们替换为上面定义的参数,因此 M 代码将如下所示:
现在您可以关闭并应用更改,您的报告应该会像以前一样工作。但是现在当你想改变数据源时,使用 Edit Parameters
:
并更改服务器 and/or 数据库名称以指向您要用于报告的其他数据源:
更改参数值后,Power BI Desktop 会要求您应用更改并从新数据源重新加载数据。要更改在 Power BI 服务中发布的报告的参数值(即数据源),请转到数据集的设置并输入新服务器 and/or 数据库名称(如果这是本地数据源,还要检查网关设置):
更改数据源后,刷新数据集以从新数据源获取数据。使用 Power BI Pro 帐户,您可以每 24 小时执行 8 次,而如果数据集位于专用容量中,则此限制提高到每 24 小时 48 次。
要以编程方式执行此操作,请使用 Update Parameters
/ Update Parameters In Group
and Refresh Dataset
/ Refresh Dataset In Group
REST API 调用。例如,您可以像这样使用 PowerShell 执行此操作:
Import-Module MicrosoftPowerBIMgmt
Import-Module MicrosoftPowerBIMgmt.Profile
$password = "xxxxx" | ConvertTo-SecureString -asPlainText -Force
$username = "xxxxx@yyyyy.com"
$credential = New-Object System.Management.Automation.PSCredential($username, $password)
Connect-PowerBIServiceAccount -Credential $credential
Invoke-PowerBIRestMethod -Url 'groups/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/datasets/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/UpdateParameters' -Method Post -Body '{
"updateDetails": [
{
"name": "ServerName",
"newValue": "SQLSERVER2019"
},
{
"name": "DatabaseName",
"newValue": "AdventureWorks2019"
}
]
}'
Invoke-PowerBIRestMethod -Url 'groups/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/datasets/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/refreshes' -Method Post
Disconnect-PowerBIServiceAccount
如果您不能使用参数,例如与 SSAS 的实时连接,可以使用 Update Datasources In Group REST API 调用更改连接字符串。在 PowerShell 中,可以这样做:
Import-Module MicrosoftPowerBIMgmt
Import-Module MicrosoftPowerBIMgmt.Profile
$password = "xxxxx" | ConvertTo-SecureString -asPlainText -Force
$username = "xxxxx@yyyyy.com"
$credential = New-Object System.Management.Automation.PSCredential($username, $password)
Connect-PowerBIServiceAccount -Credential $credential
Invoke-PowerBIRestMethod -Url 'groups/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/datasets/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Default.UpdateDatasources' -Method Post -Body '{
"updateDetails": [
{
"datasourceSelector": {
"datasourceType": "AnalysisServices",
"connectionDetails": {
"server": "My-As-Server",
"database": "My-As-Database"
}
},
"connectionDetails": {
"server": "New-As-Server",
"database": "New-As-Database"
}
}
]
}'
Disconnect-PowerBIServiceAccount
请注意,您需要提供新旧服务器和数据库名称。
在 C# 中,即使没有 Power BI 客户端,您也可以以非常相似的方式执行相同的操作:
var group_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
var dataset_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Accept", "application/json");
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
var restUrlUpdateParameters = $"https://api.powerbi.com/v1.0/myorg/groups/{group_id}/datasets/{dataset_id}/Default.UpdateParameters";
var postData = new { updateDetails = new[] { new { name = "ServerName", newValue = "NEWSERVER" }, new { name = "DatabaseName", newValue = "Another_AdventureWorks2016" } } };
var responseUpdate = client.PostAsync(restUrlUpdateParameters, new StringContent(JsonConvert.SerializeObject(postData), Encoding.UTF8, "application/json")).Result;
var restUrlRefreshDataset = $"https://api.powerbi.com/v1.0/myorg/groups/{group_id}/datasets/{dataset_id}/refreshes";
var responseRefresh = client.PostAsync(restUrlRefreshDataset, null).Result;
使用 Power BI C# 客户端可以让您的生活更轻松,例如可以这样刷新报告:
var group_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
var dataset_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
var credentials = new TokenCredentials(accessToken, "Bearer");
using (var client = new PowerBIClient(new Uri("https://api.powerbi.com"), credentials))
{
client.Datasets.RefreshDatasetInGroup(group_id, dataset_id);
}
调用API时,需要提供访问令牌。要获取它,请使用 ADAL or MSAL 库,例如使用这样的代码:
private static string resourceUri = "https://analysis.windows.net/powerbi/api";
private static string authorityUri = "https://login.windows.net/common/"; // It was https://login.windows.net/common/oauth2/authorize in prior versions
private static string clientId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; // Register at https://dev.powerbi.com/apps
private static string groupId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
private static string reportId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
private static AuthenticationContext authContext = new AuthenticationContext(authorityUri, new TokenCache());
public string Authenticate()
{
AuthenticationResult authenticationResult = null;
// First check is there token in the cache
try
{
authenticationResult = authContext.AcquireTokenSilentAsync(resourceUri, clientId).Result;
}
catch (AggregateException ex)
{
AdalException ex2 = ex.InnerException as AdalException;
if ((ex2 == null) || (ex2 != null && ex2.ErrorCode != "failed_to_acquire_token_silently"))
{
MessageBox.Show(ex.Message);
return;
}
}
if (authenticationResult == null)
{
var uc = new UserPasswordCredential("user@example.com, "Strong password");
try
{
authenticationResult = authContext.AcquireTokenAsync(resourceUri, clientId, uc).Result;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + ex.InnerException == null ? "" : Environment.NewLine + ex.InnerException.Message);
return;
}
}
if (authenticationResult == null)
MessageBox.Show("Call failed.");
else
{
return authenticationResult.AccessToken;
}
}
我有一个多租户 Web 应用程序,我正在使用每个租户一个数据库的方法。 Web 应用程序还将使用 Power BI Embedded 来显示基于特定租户数据的报告,每个租户的所有报告都将具有相同的格式,但数据源将不同。
据我所知,在 Power BI 中实现多租户并没有直接的方法,例如将数据源作为参数传递。我设法找到了两种使 Power BI 嵌入式多租户的方法。要么使用行级安全性,这意味着我需要为所有租户的数据提供一个单一的数据仓库,这对我来说不是一个选择。另一种选择是每个租户有一个工作空间。
对于第二个选项,我将有一个模板工作区,将从中为每个新租户创建一个副本。本教程介绍了如何操作:https://powerbi.microsoft.com/fr-fr/blog/duplicate-workspaces-using-the-power-bi-rest-apis-a-step-by-step-tutorial/ .
能否通过 Power BI C# SDK 完成同样的事情?我还需要更改每个工作区使用的数据源。我如何才能对我工作区中的所有报告执行此操作?
最后,有人发现了一种更简单的方法来实现嵌入 Power BI 的多租户吗?
这取决于您的数据源类型(SQL服务器、SSAS、CSV 文件等)和数据连接模式(导入、直接查询等)。如果您可以使用参数,那么您的选择之一是允许新克隆的报告使用 connection specific parameters 切换其数据源本身。为此,单击 Edit Queries
打开 Power Query Editor
,然后在 Manage Parameters
中定义两个新的文本参数,让我们将它们命名为 ServerName
和 DatabaseName
:
将它们的当前值设置为指向您的数据源之一,例如SQLSERVER2016
和 AdventureWorks2016
。然后在报告中右键单击您的查询并打开 Advanced Editor
。在M代码中找到服务器名和数据库名:
并将它们替换为上面定义的参数,因此 M 代码将如下所示:
现在您可以关闭并应用更改,您的报告应该会像以前一样工作。但是现在当你想改变数据源时,使用 Edit Parameters
:
并更改服务器 and/or 数据库名称以指向您要用于报告的其他数据源:
更改参数值后,Power BI Desktop 会要求您应用更改并从新数据源重新加载数据。要更改在 Power BI 服务中发布的报告的参数值(即数据源),请转到数据集的设置并输入新服务器 and/or 数据库名称(如果这是本地数据源,还要检查网关设置):
更改数据源后,刷新数据集以从新数据源获取数据。使用 Power BI Pro 帐户,您可以每 24 小时执行 8 次,而如果数据集位于专用容量中,则此限制提高到每 24 小时 48 次。
要以编程方式执行此操作,请使用 Update Parameters
/ Update Parameters In Group
and Refresh Dataset
/ Refresh Dataset In Group
REST API 调用。例如,您可以像这样使用 PowerShell 执行此操作:
Import-Module MicrosoftPowerBIMgmt
Import-Module MicrosoftPowerBIMgmt.Profile
$password = "xxxxx" | ConvertTo-SecureString -asPlainText -Force
$username = "xxxxx@yyyyy.com"
$credential = New-Object System.Management.Automation.PSCredential($username, $password)
Connect-PowerBIServiceAccount -Credential $credential
Invoke-PowerBIRestMethod -Url 'groups/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/datasets/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/UpdateParameters' -Method Post -Body '{
"updateDetails": [
{
"name": "ServerName",
"newValue": "SQLSERVER2019"
},
{
"name": "DatabaseName",
"newValue": "AdventureWorks2019"
}
]
}'
Invoke-PowerBIRestMethod -Url 'groups/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/datasets/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/refreshes' -Method Post
Disconnect-PowerBIServiceAccount
如果您不能使用参数,例如与 SSAS 的实时连接,可以使用 Update Datasources In Group REST API 调用更改连接字符串。在 PowerShell 中,可以这样做:
Import-Module MicrosoftPowerBIMgmt
Import-Module MicrosoftPowerBIMgmt.Profile
$password = "xxxxx" | ConvertTo-SecureString -asPlainText -Force
$username = "xxxxx@yyyyy.com"
$credential = New-Object System.Management.Automation.PSCredential($username, $password)
Connect-PowerBIServiceAccount -Credential $credential
Invoke-PowerBIRestMethod -Url 'groups/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/datasets/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Default.UpdateDatasources' -Method Post -Body '{
"updateDetails": [
{
"datasourceSelector": {
"datasourceType": "AnalysisServices",
"connectionDetails": {
"server": "My-As-Server",
"database": "My-As-Database"
}
},
"connectionDetails": {
"server": "New-As-Server",
"database": "New-As-Database"
}
}
]
}'
Disconnect-PowerBIServiceAccount
请注意,您需要提供新旧服务器和数据库名称。
在 C# 中,即使没有 Power BI 客户端,您也可以以非常相似的方式执行相同的操作:
var group_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
var dataset_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Accept", "application/json");
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
var restUrlUpdateParameters = $"https://api.powerbi.com/v1.0/myorg/groups/{group_id}/datasets/{dataset_id}/Default.UpdateParameters";
var postData = new { updateDetails = new[] { new { name = "ServerName", newValue = "NEWSERVER" }, new { name = "DatabaseName", newValue = "Another_AdventureWorks2016" } } };
var responseUpdate = client.PostAsync(restUrlUpdateParameters, new StringContent(JsonConvert.SerializeObject(postData), Encoding.UTF8, "application/json")).Result;
var restUrlRefreshDataset = $"https://api.powerbi.com/v1.0/myorg/groups/{group_id}/datasets/{dataset_id}/refreshes";
var responseRefresh = client.PostAsync(restUrlRefreshDataset, null).Result;
使用 Power BI C# 客户端可以让您的生活更轻松,例如可以这样刷新报告:
var group_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
var dataset_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
var credentials = new TokenCredentials(accessToken, "Bearer");
using (var client = new PowerBIClient(new Uri("https://api.powerbi.com"), credentials))
{
client.Datasets.RefreshDatasetInGroup(group_id, dataset_id);
}
调用API时,需要提供访问令牌。要获取它,请使用 ADAL or MSAL 库,例如使用这样的代码:
private static string resourceUri = "https://analysis.windows.net/powerbi/api";
private static string authorityUri = "https://login.windows.net/common/"; // It was https://login.windows.net/common/oauth2/authorize in prior versions
private static string clientId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"; // Register at https://dev.powerbi.com/apps
private static string groupId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
private static string reportId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
private static AuthenticationContext authContext = new AuthenticationContext(authorityUri, new TokenCache());
public string Authenticate()
{
AuthenticationResult authenticationResult = null;
// First check is there token in the cache
try
{
authenticationResult = authContext.AcquireTokenSilentAsync(resourceUri, clientId).Result;
}
catch (AggregateException ex)
{
AdalException ex2 = ex.InnerException as AdalException;
if ((ex2 == null) || (ex2 != null && ex2.ErrorCode != "failed_to_acquire_token_silently"))
{
MessageBox.Show(ex.Message);
return;
}
}
if (authenticationResult == null)
{
var uc = new UserPasswordCredential("user@example.com, "Strong password");
try
{
authenticationResult = authContext.AcquireTokenAsync(resourceUri, clientId, uc).Result;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + ex.InnerException == null ? "" : Environment.NewLine + ex.InnerException.Message);
return;
}
}
if (authenticationResult == null)
MessageBox.Show("Call failed.");
else
{
return authenticationResult.AccessToken;
}
}