Embedding PowerBI with ASP.NET Core 2 and Angular(2,4,5)

Background 


Integration of PowerBI into ASP.Net is straightforward as far as you follow the Microsoft documentation. When it comes to ASP.NET Core 2, it is not, at the time of writing this article. Let me guide you through the steps I followed to successfully embed PowerBI reports to our ASP.NET Core2 / Angular5 enterprise website.

Two Scenarios

1. User Owns Data - where users will be directly registered in PowerBi portal

2. App Owns Data - you have an application which owns the data and you have users to view these reports but they are not registered in PowerBI as direct users - ISV situation

Following steps are focused on scenario 2 which is app own data, but it is not limited to use this information for scenario 1 as well.

[Flow of authentication and authorization (from Microsoft documentation)]

Step 1: Register your app


Make sure your app is registered in Aure portal and enable PowerBI Api for that particular app.

Step 2: Get an access token


You need to have a master account - PowerBI Pro User (admin account) in PowerBi so that it will be used to connect to PowerBI Api in your application backend. If you do not have such account, create one and import your reports into that account. In this process, you will need to create PowerBI app workspace (referred as Group in the API) to organize your reports. Once you have done those, you are good to go. Above steps have been well explained in Microsoft documentation.
https://docs.microsoft.com/en-us/power-bi/developer/embedding-content

The interesting part would be getting an access token using the master account. Microsoft has provided information on how to do this in ASP.Net MVC (refer to below link), but this is just not working as UserPasswordCredential class is not available in .Net Core 2 as it does not support this approach of non-interactive authentication. Well, in this particular scenario we definitely required to authenticate master user account with username and password. In this case, we have to use non-interactive authentication by calling the OAuth Api as follows.

       

 private async Task<OAuthResult> AuthenticateAsync()
 {
  var oauthEndpoint = new Uri($"https://login.microsoftonline.com/{your org AAD Tenant ot Common}/oauth2/token");

  using (var client = new HttpClient())
  {
   var result = await client.PostAsync(oauthEndpoint, new FormUrlEncodedContent(new[]
    {
     new KeyValuePair<string,string>("resource", "https://analysis.windows.net/powerbi/api"),
     new KeyValuePair<string,string>("client_id", "your application client id"),
     new KeyValuePair<string,string>("client_secret", "your application client secret"),
     new KeyValuePair<string,string>("grant_type", "password"),
     new KeyValuePair<string,string>("username", "powerbi pro user name"),
     new KeyValuePair<string,string>("password", "powerbi pro user password"),
     new KeyValuePair<string,string>("scope", "openid")
    }
   ));

   var content = await result.Content.ReadAsStringAsync();
   return JsonConvert.DeserializeObject<OAuthResult>(content);
  }
 }

 public class OAuthResult
 {
  [JsonProperty("token_type")]
  public string TokenType { get; set; }
  [JsonProperty("scope")]
  public string Scope { get; set; }
  [JsonProperty("experies_in")]
  public int ExpiresIn { get; set; }
  [JsonProperty("ext_experies_in")]
  public int ExtExpiresIn { get; set; }
  [JsonProperty("experies_on")]
  public int ExpiresOn { get; set; }
  [JsonProperty("not_before")]
  public int NotBefore { get; set; }
  [JsonProperty("resource")]
  public Uri Resource { get; set; }
  [JsonProperty("access_token")]
  public string AccessToken { get; set; }
  [JsonProperty("refresh_token")]
  public string RefreshToken { get; set; }
 }

 

With above code, you will be able to get an access token for the master account, which will be used to generate embedding token in the next step.

Step 3: Get Embed token


Now we are going to get and embed token for a PowerBi content (it could be a report, dashboard or tile). In order to do that, you going to use PowerBI API Libraries.
https://github.com/Microsoft/PowerBI-CSharp/tree/master/sdk/PowerBI.Api

Since it is not yet supporting .Net Core, you need to download the source and build it as .Net Core library. You may need to tweak things hear and there, but it is not much effort to do this. Once you do that, you can use following code to generate embedded token to be used in your application clientside to render a PowerBi content in your application.

groupId: this is the app workspace ID and can be found when you go to the app workspace in PowerBI Portal.

reportId: his is the report unique ID and can be found when you go to the particular report in PowerBI Portal.

       
 
 public static EmbeddedReportConfig GenerateReport(string token, string groupId, string reportId, List filters)
 {
  EmbeddedReportConfig config = null;
  var tokenCredentials = new TokenCredentials(token, "Bearer");

  // Create a Power BI Client object. It will be used to call Power BI APIs.
  using (var client = new PowerBIClient(new Uri("https://api.powerbi.com"),tokenCredentials))
  {                
   Report report = client.Reports.GetReportInGroup(groupId, reportId);
   if(report != null)
   {
    var requestParameters = new GenerateTokenRequest();
    requestParameters.AccessLevel = "View";
    if (filters != null)
    {
     requestParameters.Identities = filters;
    }

    // Generate EmbedToken This function sends the POST message 
    //with all parameters and returns the token
    EmbedToken embedtoken = client.Reports.GenerateTokenInGroupAsync(
     groupId,
     reportId,
     requestParameters).GetAwaiter().GetResult();

    config = new EmbeddedReportConfig();
    config.EmbedURL = report.EmbedUrl;
    config.GroupID = groupId;
    config.ReportData = report;
    config.ReportID = reportId;
    config.Token = embedtoken?.Token;
    config.TokenID = embedtoken?.TokenId;
    config.Expiration = embedtoken?.Expiration;
   }

  }
  return config;
 }
  
 public class EmbeddedReportConfig
 {
  public string EmbedURL { get; set; }
  public string ReportID { get; set; }
  public string GroupID { get; set; }
  public Report ReportData { get; set; }
  public string Token { get; set; }
  public string TokenID { get; set; }
  public DateTime? Expiration { get; set; }

 }
 

Let's take a scenario where you want to control which user should see which report (any content) and how to apply filters (forcefully filter the data) in a particular report. You can control what user will see when they access the report. As you already have realized that, we only create embed token for the resource that we want to show to the user, but how to control the data in it?

Request parameters (or filters in the above code snippet) are going to rescue you.

How do these filters work?
There is using the RLS (Row-level security) built into the PowerBi. It uses "Role"s to handle this. Once you have roles, you can easily pass these roles (more than one) when you generate the embed token, where it will be embedded into the Embed Token.

When user views the report using embed token, PowerBi will apply roles in the token, so that user will only see filtered data accordingly. You can read following documentation to understand more. Please note that, you have to use PowerBI desktop app to set up these roles.
https://docs.microsoft.com/en-us/power-bi/service-admin-rls

Let's see how to construct these filters.

 
 
 [Authorize]
 [Route("api/Report/EmbedReport")]
 [HttpGet(Name = "EmbedReport")]
 public EmbeddedReportConfig EmbedReport(string groupid, string reportid)
 {
  EmbeddedReportConfig report = null;
  if( User has access )
  {
   var proUserToken = AuthenticateAsync().GetAwaiter().GetResult();
   List<effectiveidentity> filters = new List<effectiveidentity>();
   filters.Add(new EffectiveIdentity
   {
    Username = "user id or email",
    Roles = new List<string> { "Category1Role", "Category2Role" },
    Datasets = new List<string> { "data set ID" }
   });
   report = GenerateReport(proUserToken.AccessToken, groupid, reportid, filters);
  }
  return report;
 }

 

Here you have control over user, roles and datasets. This is pretty much all you need to control what needs to be shown to user according to access privileges.

Step 4: Render the report in client-side (front-end)


GenerateReport method returns what you need to render the report using PowerBI Javascript library. Since I'm using Angular5 for my project, I'll explain how you could achieve this in Angular5. If you need just pure Javascript, you can get the JS library to do that as well.

Add PowerBI client package to your project in Angular ("powerbi-client": "^2.4.7"). Then use following code to get it rendered.

 
 

 // you need : "powerbi-client": "^2.4.7"
 
 import * as pbi from 'powerbi-client';

 powerbi: pbi.service.Service;
 
 embedReportConfig = http.get("api/Report/EmbedReport"); call you server to get the embed token
 
 var config:pbi.IEmbedConfiguration = {
  type: 'report',
  tokenType: pbi.models.TokenType.Embed,
  accessToken: "embedded token you generated in your server side :: embedReportConfig.token",
  embedUrl: "Report Url :: embedReportConfig.embedURL",
  id: "Report ID :: embedReportConfig.reportID",
  permissions: pbi.models.Permissions.Read,
  pageName: "Whatever your page name",                    
  settings: {
   filterPaneEnabled: false, // this will show/hide filter options
   navContentPaneEnabled: true                        
  }
 };
 let reportContainer = <HTMLElement>document.getElementById('powerBIReportContainer');
 this.powerbi.embed(reportContainer, config);
 
 <div id="powerBIReportContainer" class="d-block container-fluid m-0 p-0"></div>
 
 

Hope this will help to integrate PowerBI to your ASP.Net Core 2 application without any issue.

Comments

  1. Can you explain how to print this report in Angular?

    ReplyDelete
  2. there one or two errors in your code...

    ReplyDelete

Post a Comment

Popular posts from this blog

Handling Exit Event of Console Application in C#

Taxi - Cab services in Colombo - Sri Lanka