March 31 - April 2, 2025, in Las Vegas, Nevada. Use code MSCUST for a $150 discount! Early bird discount ends December 31.
Register NowBe one of the first to start using Fabric Databases. View on-demand sessions with database experts and the Microsoft product team to learn just how easy it is to get started. Watch now
Hello,
I just succeed to integrate Power Bi Report into an app following examples given on powerbi.com.
(https://msdn.microsoft.com/en-us/library/azure/dn645542.aspx)
(https://github.com/Microsoft/PowerBI-CSharp)
Right now, the user had to authenticate to get an authentication code, then I can get an access_token which allows me to get my report and to publish it.
However I would like to integrate report without asking the user to authenticate.
I tried to use an other method (https://msdn.microsoft.com/en-us/library/azure/dn645543.aspx) to get a token but I only got response 403 Forbidden when I was asking the Power Bi API to get my report.
I found a related topic with a potential solution to my problem :
http://community.powerbi.com/t5/Developer/How-to-use-Power-BI-Rest-API-without-GUI-authentication-re...
But when I try it, I am getting a weird? error :
Error: https://app.powerbi.com/13.0.1100.519/scripts/powerbiportal.dependencies.bundle.min.js is being assigned a //# sourceMappingURL, but already has one Error: https://app.powerbi.com/13.0.1100.519/scripts/powerbiportal.common.bundle.min.js is being assigned a //# sourceMappingURL, but already has one Error: https://app.powerbi.com/13.0.1100.519/scripts/powerbiportal.explore.bundle.min.js is being assigned a //# sourceMappingURL, but already has one Error: https://app.powerbi.com/13.0.1100.519/scripts/powerbireportembed.common.bundle.min.js is being assigned a //# sourceMappingURL, but already has one Error: https://app.powerbi.com/13.0.1100.519/scripts/ODataExplore.min.js is being assigned a //# sourceMappingURL, but already has one // Weird Error coming from JS ?? "AI: USRACT_StringValueTooLong message:"string value is too long. It has been truncated to 1024 characters." props:"{value:f3eee70c-fa06-4f54-aae8-19f58fd9025feyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik1uQ19WWmNBVGZNNXBPWWlKSE1iYTlnb0VLWSIsImtpZCI6Ik1uQ19WWmNBVGZNNXBPWWlKSE1iYTlnb0VLWSJ9.eyJhdWQiOiJodHRwczovL2FuYWx5c2lzLndpbmRvd3MubmV0L3Bvd2VyYmkvYXBpIiwiaXNzIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvNTEwNDM0MzItYzJlMC00YmE5LWE4NGYtMmY3NWVhZjIyMDdmLyIsImlhdCI6MTQ2Mjk1MDcyOCwibmJmIjoxNDYyOTUwNzI4LCJleHAiOjE0NjI5NTQ2MjgsImFjciI6IjEiLCJhbXIiOlsicHdkIl0sImFwcGlkIjoiYmExNzgzMjctMmE2Ni00NWU1LWJiY2ItZDczZWVmYTdjYjRkIiwiYXBwaWRhY3IiOiIxIiwiZmFtaWx5X25hbWUiOiJCdXNpbmVzc1NoYXJlIiwiZ2l2ZW5fbmFtZSI6IlN1cHBvcnQiLCJpcGFkZHIiOiI1LjEzNS4xNDIuMjI3IiwibmFtZSI6IlN1cHBvcnQgQnVzaW5lc3NTaGFyZSIsIm9pZCI6ImYyNmY0YzRmLWRmZGEtNGVlMC05Mjc2LTgzZjk0ZTE3M2Q4YiIsInB1aWQiOiIxMDAzM0ZGRjhDNTIyN0ZEIiwic2NwIjoiRGFzaGJvYXJkLlJlYWQuQWxsIERhdGFzZXQuUmVhZC5BbGwgTWV0YWRhdGEuVmlld19BbnkgUmVwb3J0LlJlYWQuQWxsIiwic3ViIjoiOGU0YjI0YkFoUUNNLVFoaUplekhYVGFNVEMzeGctekhwLXpRd1QxSE96WSIsInRpZCI6IjUxMDQzNDMyLWMyZTAtNGJhOS1hODRmLTJmNzVlYWYyMjA3ZiIsInVuaXF1ZV9uYW1lIjoic3VwcG9ydEBidXNpbmV}"" ai.0.js:1 "AI: USRACT_StringValueTooLong message:"string value is too long. It has been truncated to 1024 characters." props:"{value:f3eee70c-fa06-4f54-aae8-19f58fd9025feyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik1uQ19WWmNBVGZNNXBPWWlKSE1iYTlnb0VLWSIsImtpZCI6Ik1uQ19WWmNBVGZNNXBPWWlKSE1iYTlnb0VLWSJ9.eyJhdWQiOiJodHRwczovL2FuYWx5c2lzLndpbmRvd3MubmV0L3Bvd2VyYmkvYXBpIiwiaXNzIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvNTEwNDM0MzItYzJlMC00YmE5LWE4NGYtMmY3NWVhZjIyMDdmLyIsImlhdCI6MTQ2Mjk1MDcyOCwibmJmIjoxNDYyOTUwNzI4LCJleHAiOjE0NjI5NTQ2MjgsImFjciI6IjEiLCJhbXIiOlsicHdkIl0sImFwcGlkIjoiYmExNzgzMjctMmE2Ni00NWU1LWJiY2ItZDczZWVmYTdjYjRkIiwiYXBwaWRhY3IiOiIxIiwiZmFtaWx5X25hbWUiOiJCdXNpbmVzc1NoYXJlIiwiZ2l2ZW5fbmFtZSI6IlN1cHBvcnQiLCJpcGFkZHIiOiI1LjEzNS4xNDIuMjI3IiwibmFtZSI6IlN1cHBvcnQgQnVzaW5lc3NTaGFyZSIsIm9pZCI6ImYyNmY0YzRmLWRmZGEtNGVlMC05Mjc2LTgzZjk0ZTE3M2Q4YiIsInB1aWQiOiIxMDAzM0ZGRjhDNTIyN0ZEIiwic2NwIjoiRGFzaGJvYXJkLlJlYWQuQWxsIERhdGFzZXQuUmVhZC5BbGwgTWV0YWRhdGEuVmlld19BbnkgUmVwb3J0LlJlYWQuQWxsIiwic3ViIjoiOGU0YjI0YkFoUUNNLVFoaUplekhYVGFNVEMzeGctekhwLXpRd1QxSE96WSIsInRpZCI6IjUxMDQzNDMyLWMyZTAtNGJhOS1hODRmLTJmNzVlYWYyMjA3ZiIsInVuaXF1ZV9uYW1lIjoic3VwcG9ydEBidXNpbmV}"" ai.0.js:1
I don't understand where it came from : the token is 1407 characters long with this method but it is the same with the method that work well (the first one with authentication)
Hope you can help me,
Wahid
Here is my code if it can help you to help me ^^ :
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// C# PART : using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using Microsoft.IdentityModel.Clients.ActiveDirectory; using System.Threading.Tasks; using System.Net.Http; using System.Collections.Specialized; using Newtonsoft.Json; using System.Text; using System.IO; namespace PBIWebApp { public partial class _Default : Page { string baseUri = "https://api.powerbi.com/beta/myorg/"; string Token; private async void SetAccessToken() { List<KeyValuePair<string, string>> vals = new List<KeyValuePair<string, string>>(); vals.Add(new KeyValuePair<string, string>("grant_type", "password")); vals.Add(new KeyValuePair<string, string>("scope", "openid")); vals.Add(new KeyValuePair<string, string>("resource", "https://analysis.windows.net/powerbi/api")); vals.Add(new KeyValuePair<string, string>("client_id", Properties.Settings.Default.ClientID)); vals.Add(new KeyValuePair<string, string>("client_secret", Properties.Settings.Default.ClientSecret)); vals.Add(new KeyValuePair<string, string>("username", "<MYUSERNAME>")); vals.Add(new KeyValuePair<string, string>("password", "<MYPASSWORD>")); string TenantId = Properties.Settings.Default.TenantID; string url = string.Format("https://login.windows.net/{0}/oauth2/token", TenantId); HttpClient hc = new HttpClient(); HttpContent content = new FormUrlEncodedContent(vals); HttpResponseMessage hrm = hc.PostAsync(url, content).Result; string responseData = ""; if (hrm.IsSuccessStatusCode) { Stream data = await hrm.Content.ReadAsStreamAsync(); using (StreamReader reader = new StreamReader(data, Encoding.UTF8)) { responseData = reader.ReadToEnd(); } } Token = responseData; } protected void Page_Load(object sender, EventArgs e) { SetAccessToken(); getReportsButton_Click(); } protected void getReportsButton_Click()//getReportsButton_Click(object sender, EventArgs e) { string responseContent = string.Empty; //Configure reports request System.Net.WebRequest request = System.Net.WebRequest.Create(String.Format("{0}reports", baseUri)) as System.Net.HttpWebRequest; request.Method = "GET"; request.ContentLength = 0; var acctoken = Token.Split(','); var split = acctoken[6].Split('"'); var access = split[3]; // access give me the access_token I need to get the information I am asking for. request.Headers.Add("Authorization", String.Format("Bearer {0}", access)); //Get reports response from request.GetResponse() using (var response = request.GetResponse() as System.Net.HttpWebResponse) { //Get reader from response stream using (var reader = new System.IO.StreamReader(response.GetResponseStream())) { responseContent = reader.ReadToEnd(); //Deserialize JSON string PBIReports PBIReports = JsonConvert.DeserializeObject<PBIReports>(responseContent); tb_reportsResult.Text = string.Empty; //Get each report foreach (PBIReport rpt in PBIReports.value) { if (rpt.name.Contains("TestIframe")) { // This step is OK, I can get the embedUrl I am asking for and the access_token tb_reportsResult.Text += String.Format("{0}\t{1}", rpt.embedUrl, access); } } } } } } public class AccessToken { public string token_type; public string scope { get; set; } public string expires_in { get; set; } public string expires_on { get; set; } public string not_before { get; set; } public string resource { get; set; } public string access_token { get; set; } public string refresh_token { get; set; } public string id_token { get; set; } } //Power BI Datasets public class PBIDatasets { public Dataset[] Datasets { get; set; } } public class PBIGroups { public PBIGroup[] value { get; set; } } public class Dataset { public string Id { get; set; } public string Name { get; set; } } public class PBIGroup { public string id { get; set; } public string name {get; set;} } public class PBIDashboards { public PBIDashboard[] value { get; set; } } public class PBIDashboard { public string id { get; set; } public string displayName { get; set; } } public class PBIReports { public PBIReport[] value { get; set; } } public class PBIReport { public string id { get; set; } public string name { get; set; } public string webUrl { get; set; } public string embedUrl { get; set; } } public class PBITiles { public PBITile[] value { get; set; } } public class PBITile { public string id { get; set; } public string title { get; set; } public string embedUrl { get; set; } } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// JS part : <%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs" Inherits="PBIWebApp.SiteMaster" %> <!DOCTYPE html> <html lang="en"> <head runat="server"> <title>Power BI - Web application</title> <script type="text/javascript"> window.onload = function () { // listen for message to receive message from embedded report. if (window.addEventListener) { window.addEventListener("message", receiveMessage, false); } else { window.attachEvent("onmessage", receiveMessage); } // handle server side post backs, optimize for reload scenarios // show embedded report if all fields were filled in. var report = document.getElementById('MainContent_tb_reportsResult').value; var tableau = report.split("\t"); var accessTokenElement = tableau[1]; console.log("textbox " + accessTokenElement + " report " + report); if(null !== accessTokenElement){ if ("" !== accessTokenElement) console.log("JE SUIS LA"); updateEmbedReport(); } }; // The embedded report posts message for errors to parent window. listen and handle as appropriate function receiveMessage(event) { if (event.data) { try { messageData = JSON.parse(event.data); if (messageData.event === "reportPageLoaded") { } } catch (e) { // do something smart } } } var valB = false; // update embed report function updateEmbedReport() { // check if the embed url was selected //Console.WriteLine("doc : "+document.getElementById('tb_reportsResult').value) var embedUrl = document.getElementById('MainContent_tb_reportsResult').value; if ("" === embedUrl) return; // to load a report do the following: // 1: set the url // 2: add a onload handler to submit the auth token iframe = document.getElementById('iFrameEmbedReport'); iframe.src=embedUrl; console.log("ok1"); iframe.onload = postActionLoadReport; console.log("ok2"); } // post the auth token to the iFrame. function postActionLoadReport() { // get the access token. var report = document.getElementById('MainContent_tb_reportsResult').value; var tableau = report.split("\t"); var accessTokenElement = tableau[1]; accessToken = accessTokenElement; // return if no a if ("" === accessToken) return; // construct the push message structure // this structure also supports setting the reportId, groupId, height, and width. // when using a report in a group, you must provide the groupId on the iFrame SRC var m = { action: "loadReport", accessToken: accessToken}; message = JSON.stringify(m); console.log(message); // push the message. iframe = document.getElementById('iFrameEmbedReport'); iframe.contentWindow.postMessage(message, "*"); //<== My error came from the line above } </script> </head> <body> <form runat="server"> <div> <asp:ContentPlaceHolder ID="Stylesheets" runat="server"> <link rel="stylesheet" href="/css/master.css" type="text/css" /> </asp:ContentPlaceHolder> <asp:ContentPlaceHolder ID="MainContent" runat="server"> </asp:ContentPlaceHolder> </div> </form> </body> </html>
Can you please clarify what the TenantId represents in the above code..
If you do not want to authenticate, why not just use the Publish to Web feature and essentially iframe it?
I tried to use the Publish to Web feature but it seems that with this feature I won't be able to filter the report like I am doing it right now.(Except if you know a way to add filter on a publish to web report ? But I didn't find it if this way exist)
March 31 - April 2, 2025, in Las Vegas, Nevada. Use code MSCUST for a $150 discount!
Your insights matter. That’s why we created a quick survey to learn about your experience finding answers to technical questions.
Arun Ulag shares exciting details about the Microsoft Fabric Conference 2025, which will be held in Las Vegas, NV.
User | Count |
---|---|
7 | |
3 | |
2 | |
1 | |
1 |