0
votes

I'm doing some R&D with a power BI Visual Studio solution and I'm struggling to programmatically embed content. I have the Power BI Pro trial.

From the Embed Setup webpage, I created an application ("User owns Data" with sample data) and downloaded the sample VS solution which comes configured with the GUIDs for the app that was just created. The app appears in my Power BI web interface and when I run the VS web app, I get three buttons (embed report | embed dashboard | embed tile). This works - I can view the embedded report.

My problem is when I install an app using the Power BI interface and then try to run my VS project using the appId of the app I just installed. For example - I installed the Github app and chose to use sample data. If I plug in the appId, workspace Id and report Id into my VS project, I get the following message when I run it and click the "Embed Report" button

AADSTS700016: Application with identifier '5c7d26d1-006d-43ac-9eb7-6aa3e1f6b364' was not found in the directory 'foo.onmicrosoft.com'. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You may have sent your authentication request to the wrong tenant.
Trace ID: e77376aa-b7ca-4c09-9184-31f96eea9800
Correlation ID: d42a0b9c-c93d-4601-87d6-05d9cca70e0d
Timestamp: 2019-06-04 15:59:58Z

Why is it that an app I created using the "Embed Setup" page works, but a different app's Ids fail with that error? I am using the same login credentials in the VS project as I am logging into the Power BI website with, as well as when I created an app with the "Embed Setup" page.

Could it be that it is looking for an app that is registered in my Azure portal under the Active directory > App Registrations? If so, why does the other Power BI app work (Embed Setup route)?

When I tested creating an app using "App Owns Data", the application was registered in my Azure AD

As a side note - is there an easy way to get app, workspace and report Ids for an app? AppId is easy enough to grab from the URL, but workspace Id never seems to appear

UPDATE After using the 'onboarding embed tool' as suggested @Andrey, I do see the application registered in Azure, but if I replace the applicationId web.config key with the Id of the Azure application, I get a different error message (below). I'm confident that the applicationId int the web.config of the generated project is specifically the (Power BI) App Id and not the Azure Application Id (not confusing at all, Microsoft!). Using the Azure Application Id, I get the following error:

Error
            AADSTS7000218: The request body must contain the following parameter: 'client_assertion' or 'client_secret'.
Trace ID: 5e8391c2-4681-4c8e-9294-a99fd56dbb00
Correlation ID: 10d48927-d5ec-45bd-a5b3-e9c1e147f97c
Timestamp: 2019-06-05 15:29:44Z

I feel like there is documentation that I need but can't find. I've created the Application that appears in Azure (I had done this before, but could not find any connection between this application and my PowerBI page). I've created apps, workspaces, and reports in Power BI. All I want to do is use the .Net SDK to pull in visualisations from a specific Power BI installation i.e. insert a visualisation of a client's data onto their website.

I'll keep digging and update when I find a solution

2

2 Answers

1
votes

You are mixing two different "app ids". First app ID (also called client ID) is the one that you are registering in the onboarding embed tool (https://dev.powerbi.com/apps), which I believe is what you called "Embed Setup" (or embed setup is something on top of that). This app registrations will be visible in Azure AD after that. The other "app" that you mention is "Power BI App", i.e. a collection of reports that are packed together in an app. These two "apps" are completely different and you can't use the ID of the later one when embedding Power BI elements.

When you open a report saved in a workspace, the URL will be in the following format:

https://app.powerbi.com/groups/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/reports/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/ReportSection

First guid (the x-es after groups) is the workspace ID (also called group ID). The later one (after reports) is the report ID. There is no "workspace and report Ids for an app", because your app (the one that you registered and is visible in Azure AD) can access various reports in various workspaces. The reports packed in a "Power BI app" should be embedded from their original workspace, not from the app.

0
votes

I eventually found the solution I was looking for. Essentially you use the PowerBI C# SDK to authenticate and return your PowerBI data - like collections of reports, which you can then embed using the JS API

private async Task<AuthenticationResult> DoAuthentication()
{
    AuthenticationResult authenticationResult = null;
    if (AuthenticationType.Equals("MasterUser"))
    {
        var authenticationContext = new AuthenticationContext(AuthorityUrl);

        // Authentication using master user credentials
        var credential = new UserPasswordCredential(Username, Password);
        authenticationResult = authenticationContext.AcquireTokenAsync(ResourceUrl, ApplicationId, credential).Result;
    }
    else
    {
        // For app only authentication, we need the specific tenant id in the authority url
        var tenantSpecificURL = AuthorityUrl.Replace("common", Tenant);
        var authenticationContext = new AuthenticationContext(tenantSpecificURL);

        // Authentication using app credentials
        var credential = new ClientCredential(ApplicationId, ApplicationSecret);
        authenticationResult = await authenticationContext.AcquireTokenAsync(ResourceUrl, credential);
    }

    return authenticationResult;
}

then, to get a list of reports

    public IList<Report> GetReportsByGroup(string groupId)
    {
        if (_reports == null)
        {
            var Client = new PowerBIClient(new Uri(ApiUrl), new TokenCredentials(AccessToken, "Bearer"));
            _reports = Client.Reports.GetReportsInGroup(groupId).Value;
        }
        return _reports;
    }