I am trying to create a C# HTTP-triggered Function from the Azure portal (Embedded Analytics with Power BI). I follow the post of Taygan ( https://www.taygan.co/blog/2018/05/14/embedded-analytics-with-power-bi ) and using the ref for System.Web.Extensions but it throw:
Metadata file 'System.Web.Extensions' could not be found
This is the code:
#r "System.Web.Extensions"
using System.Configuration;
using System.Net;
using System.Text;
using System.Web.Script.Serialization;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Microsoft.PowerBI.Api.V2;
using Microsoft.PowerBI.Api.V2.Models;
using Microsoft.Rest;
// Static Values
static string authorityUrl = "https://login.windows.net/common/oauth2/authorize/";
static string resourceUrl = "https://analysis.windows.net/powerbi/api";
static string apiUrl = "https://api.powerbi.com/";
static string clientId = ConfigurationManager.AppSettings["PBIE_CLIENT_ID"];
static string username = ConfigurationManager.AppSettings["PBIE_USERNAME"];
static string password = ConfigurationManager.AppSettings["PBIE_PASSWORD"];
static string groupId = ConfigurationManager.AppSettings["PBIE_GROUP_ID"];
static string reportId = ConfigurationManager.AppSettings["PBIE_REPORT_ID"];
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
// Authenticate with Azure Ad > Get Access Token > Get Token Credentials
var credential = new UserPasswordCredential(username, password);
var authenticationContext = new AuthenticationContext(authorityUrl);
var authenticationResult = await authenticationContext.AcquireTokenAsync(resourceUrl, clientId, credential);
string accessToken = authenticationResult.AccessToken;
var tokenCredentials = new TokenCredentials(accessToken, "Bearer");
using (var client = new PowerBIClient(new Uri(apiUrl), tokenCredentials))
{
// Embed URL
Report report = client.Reports.GetReportInGroup(groupId, reportId);
string embedUrl = report.EmbedUrl;
// Embed Token
var generateTokenRequestParameters = new GenerateTokenRequest(accessLevel: "view");
EmbedToken embedToken = client.Reports.GenerateTokenInGroup(groupId, reportId, generateTokenRequestParameters);
// JSON Response
EmbedContent data = new EmbedContent();
data.EmbedToken = embedToken.Token;
data.EmbedUrl = embedUrl;
data.ReportId = reportId;
JavaScriptSerializer js = new JavaScriptSerializer();
string jsonp = "callback(" + js.Serialize(data) + ");";
// Return Response
return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(jsonp, Encoding.UTF8, "application/json")
};
}
}
public class EmbedContent
{
public string EmbedToken { get; set; }
public string EmbedUrl { get; set; }
public string ReportId { get; set; }
}
How can I fix it? Please help me, thank you.
Problem is caused by the difference of Function runtime.
The tutorial you follow creates function on ~1 runtime where code targets at .NET Framework , while the one you create is on ~2 runtime which runs on .NET Core env. When we create a new Function app its runtime is set to ~2 by default now.
Solution is to set FUNCTIONS_EXTENSION_VERSION
to ~1
in Application settings on portal.
To achieve that in ~2 runtime, create a httptrigger in ~2 and replace the sample code with snippet below. Note you also have to add PBIE_TENANT_ID
in Application settings with value get from Azure Active Directory> Properties>Directory ID.
#r "Newtonsoft.Json"
using System.Net;
using System.Text;
using Newtonsoft.Json;
static string resourceUrl = "https://analysis.windows.net/powerbi/api";
static string clientId = Environment.GetEnvironmentVariable("PBIE_CLIENT_ID");
static string username = Environment.GetEnvironmentVariable("PBIE_USERNAME");
static string password = Environment.GetEnvironmentVariable("PBIE_PASSWORD");
static string groupId = Environment.GetEnvironmentVariable("PBIE_GROUP_ID");
static string reportId = Environment.GetEnvironmentVariable("PBIE_REPORT_ID");
static string tenantId = Environment.GetEnvironmentVariable("PBIE_TENANT_ID");
static string tokenEndpoint = $"https://login.microsoftonline.com/{tenantId}/oauth2/token";
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, ILogger log)
{
// Get access token
HttpClient authclient = new HttpClient();
log.LogInformation(resourceUrl);
log.LogInformation(tokenEndpoint);
var authContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("grant_type", "password"),
new KeyValuePair<string, string>("username", username),
new KeyValuePair<string, string>("password", password),
new KeyValuePair<string, string>("client_id", clientId),
new KeyValuePair<string, string>("resource", resourceUrl)
});
var accessToken = await authclient.PostAsync(tokenEndpoint, authContent).ContinueWith<string>((response) =>
{
log.LogInformation(response.Result.StatusCode.ToString());
log.LogInformation(response.Result.ReasonPhrase.ToString());
log.LogInformation(response.Result.Content.ReadAsStringAsync().Result);
AzureAdTokenResponse tokenRes =
JsonConvert.DeserializeObject<AzureAdTokenResponse>(response.Result.Content.ReadAsStringAsync().Result);
return tokenRes?.AccessToken;
});
// Get PowerBi report url and embed token
HttpClient powerBiClient = new HttpClient();
powerBiClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {accessToken}");
log.LogInformation(accessToken);
var embedUrl =
await powerBiClient.GetAsync($"https://api.powerbi.com/v1.0/myorg/groups/{groupId}/reports/{reportId}")
.ContinueWith<string>((response) =>
{
log.LogInformation(response.Result.StatusCode.ToString());
log.LogInformation(response.Result.ReasonPhrase.ToString());
PowerBiReport report =
JsonConvert.DeserializeObject<PowerBiReport>(response.Result.Content.ReadAsStringAsync().Result);
return report?.EmbedUrl;
});
var tokenContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("accessLevel", "view")
});
var embedToken = await powerBiClient.PostAsync($"https://api.powerbi.com/v1.0/myorg/groups/{groupId}/reports/{reportId}/GenerateToken", tokenContent)
.ContinueWith<string>((response) =>
{
log.LogInformation(response.Result.StatusCode.ToString());
log.LogInformation(response.Result.ReasonPhrase.ToString());
PowerBiEmbedToken powerBiEmbedToken =
JsonConvert.DeserializeObject<PowerBiEmbedToken>(response.Result.Content.ReadAsStringAsync().Result);
return powerBiEmbedToken?.Token;
});
// JSON Response
EmbedContent data = new EmbedContent
{
EmbedToken = embedToken,
EmbedUrl = embedUrl,
ReportId = reportId
};
string jsonp = "callback(" + JsonConvert.SerializeObject(data) + ");";
// Return Response
return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(jsonp, Encoding.UTF8, "application/json")
};
}
public class AzureAdTokenResponse
{
[JsonProperty("access_token")]
public string AccessToken { get; set; }
}
public class PowerBiReport
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "webUrl")]
public string WebUrl { get; set; }
[JsonProperty(PropertyName = "embedUrl")]
public string EmbedUrl { get; set; }
[JsonProperty(PropertyName = "datasetId")]
public string DatasetId { get; set; }
}
public class PowerBiEmbedToken
{
[JsonProperty(PropertyName = "token")]
public string Token { get; set; }
[JsonProperty(PropertyName = "tokenId")]
public string TokenId { get; set; }
[JsonProperty(PropertyName = "expiration")]
public DateTime? Expiration { get; set; }
}
public class EmbedContent
{
public string EmbedToken { get; set; }
public string EmbedUrl { get; set; }
public string ReportId { get; set; }
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.