Get requests to api stuck on pending - c#

I apologize in advance for the bad editing skills, I'm new at posting questions
I'm trying to call my c# api from an angular app, however the request is stuck on pending. I don't think theres a mistake in my typescript code but I'm new to c# so it might be something to do with the api, possibly because of the asyncs.
Here's the api code
{
private static readonly string Tenant = "https://login.microsoftonline.com/{azure.tenant}/";
private static readonly string Resource = "https://analysis.windows.net/powerbi/api";
private string getToken()
{
var authContext = new AuthenticationContext(Tenant);
var clientCredential = new ClientCredential(AppId, AppSecret);
var token = authContext.AcquireTokenAsync(Resource, clientCredential);
return token.Result.AccessToken;
}
private PowerBIClient getPBIClient()
{
var token = new TokenCredentials(getToken(), "Bearer");
return new PowerBIClient(new Uri("https://api.powerbi.com/"), token);
}
public async Task<ODataResponseListReport> getReportsAsync(string ws)
{
PowerBIClient pbiClient = getPBIClient();
var reports = await pbiClient.Reports.GetReportsInGroupAsync(ws);
return reports;
}
public async Task<ReportEmbeddingData> getReportEmbeddingDataAsync(string ws, string rep)
{
PowerBIClient pbiClient = getPBIClient();
var report = await pbiClient.Reports.GetReportInGroupAsync(ws, rep);
var embedUrl = report.EmbedUrl;
var reportName = report.Name;
GenerateTokenRequest genTokenReqParam = new GenerateTokenRequest(accessLevel: "view");
string embedToken = (await pbiClient.Reports.GenerateTokenInGroupAsync(ws, rep, genTokenReqParam)).Token;
return new ReportEmbeddingData {
reportId = rep,
reportName = reportName,
embedUrl = embedUrl,
accessToken = embedToken
};
}
}
And here is my angular call that's being done on ngOnInit
getReports(){
this.http.get("http://localhost:44391/api/Auth?ws="+this.workspaceId)
.subscribe((response) => {
this.reportArray = response;
console.log(this.reportArray);
});
}

Related

"Insufficient priveleges to complete the operation", inspite of granting all necessary permissions

{"odata.error":{"code":"Authorization_RequestDenied",
"message":
{"lang":"en","value":"Insufficient privileges to complete the operation."},
"requestId":"b205e5d0-f929-418e-9153-f1994e2c0893",
"date":"2020-02-15T06:53:57"}
}
I am able to retrieve the authentication token from the server and have granted all the permissions through the AAD but still I'm facing the same issue.
Would be great if someone could help me out.
I am using the Microsoft Graph API.
Below is the code that I am using
private const string clientID = "XXXX";
private const string addInstance = "https://login.microsoftonline.com/{0}";
private const string tenant = "XYZ";
private const string resource = "https://graph.windows.net";
private const string appKey = "appkey";
static string authority = String.Format(CultureInfo.InvariantCulture, addInstance, tenant);
private static HttpClient httpclient = new HttpClient();
private static AuthenticationContext context = null;
private static ClientCredential credential = null;
static void Main(string[] args)
{
context = new AuthenticationContext(authority);
credential = new ClientCredential(clientID,appKey);
Task<string> token = GetToken();
token.Wait();
Console.WriteLine(token.Result);
Task<string> users = GetUsers(token.Result);
users.Wait();
Console.WriteLine(users.Result);
//Console.ReadLine();
}
private static async Task<string> GetUsers(string result)
{
string users = null;
string queryString = "api-version=1.6";
var uri = "https://graph.windows.net/ *The Microsoft 365 account assosciated with the tenant* /users?"+ queryString;
httpclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result);
var getResult = await httpclient.GetAsync(uri);
if (getResult != null)
{
users = await getResult.Content.ReadAsStringAsync();
}
return users;
}
private static async Task<string> GetToken()
{
AuthenticationResult result = null;
string token = null;
result = await context.AcquireTokenAsync(resource, credential);
token = result.AccessToken;
return token;
}
}
I have tried following way and perfectly worked for me.
//Token Request End Point
string tokenUrl = $"https://login.microsoftonline.com/yourTenant.onmicrosoft.com/oauth2/token";
var tokenRequest = new HttpRequestMessage(HttpMethod.Post, tokenUrl);
//I am Using client_credentials as It is mostly recommended
tokenRequest.Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
["grant_type"] = "client_credentials",
["client_id"] = "b603c7be-a956_Your_Client_Id_a45996-e6921e61f36955",
["client_secret"] = "Vxf1SluKbgu4PF0loj_Your_Client_Secret_okjh8wL/yujh45lojhgg=",
["resource"] = "https://graph.windows.net"
});
dynamic json;
AccessTokenClass results = new AccessTokenClass();
HttpClient client = new HttpClient();
var tokenResponse = await client.SendAsync(tokenRequest);
json = await tokenResponse.Content.ReadAsStringAsync();
results = JsonConvert.DeserializeObject<AccessTokenClass>(json);
//New Block For Accessing Data from Microsoft Graph Rest API
HttpClient _client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, string.Format("https://graph.windows.net/YourTenant.onmicrosoft.com/users?api-version=1.6"));
//Passing Token For this Request
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", results.access_token);
//Check The Response and extract response data
HttpResponseMessage response = await _client.SendAsync(request);
dynamic objGpraphUserList = JsonConvert.DeserializeObject<dynamic>(await response.Content.ReadAsStringAsync());
return objGpraphUserList
Class Used:
public class AccessTokenClass
{
public string token_type { get; set; }
public string expires_in { get; set; }
public string resource { get; set; }
public string access_token { get; set; }
}
I got the User List as expected. See the screen shot.
Validate Your Token :
Check your token on https://jwt.io/ which should have User.ReadWrite.All or User.Read.All Application permission
Note:
You should have following permission on Azure Active Directory Graph
For more information please refer to this official document
Hope this would help.

Not getting all users from the AAD when trying to get user list by using MSGrpah API

Here is my code which is pulling only 100 users from the active directory. I have granted the "read all user profile permission" in application and delegated sections as well.
namespace MVCDemoGraphAPI.Controllers
{
public class HomeController : Controller
{
private static string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
private static string aadInstance = ConfigurationManager.AppSettings["ida:AADInstance"];
private static string tenant = ConfigurationManager.AppSettings["ida:Tenant"];
private static string appKey = ConfigurationManager.AppSettings["ida:AppKey"];
public async Task<string> Users()
{
string authority = string.Format(CultureInfo.InvariantCulture, aadInstance, tenant);
AuthenticationContext authContext = new AuthenticationContext(authority);
AuthenticationResult result = null;
try
{
result = await authContext.AcquireTokenAsync("https://graph.microsoft.com",
new ClientCredential(clientId, appKey));
}
catch (Exception)
{
throw;
}
//Now call the Graph API
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/users");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
HttpResponseMessage response = await client.SendAsync(request);
string output = await response.Content.ReadAsStringAsync();
return output;
}
}
}
You have to use Paging filters as described in here:
https://learn.microsoft.com/en-us/previous-versions/azure/ad/graph/howto/azure-ad-graph-api-supported-queries-filters-and-paging-options ,
mainly paging forward.
I recommend to use c# graph client Nuget and then use the code below:
var users = await graphClient.Users.Request().GetAsync();
try
{
while (users != null)
{
var usersList = users.CurrentPage.ToList();
count = count + usersList.Count();
users = await users.NextPageRequest.GetAsync();
}
}
catch
{
//
}

How to cache a request in ASP.NET Core?

I am looking for how to cache a request in ASP.NET Core 2.x?
I have API proxy which always return a different response using the same request (synonyms composition using an AI, hence that's why I am not looking for caching the response).
And I would like to cache the request since it's always the same (always the same basic auth and parameters to poke the other API that I am proxy-ing).
Since the request use a file input.xml for the parameters, I am wondering where I can cache that one as well
My controller:
[Route("api/v1/[controller]")]
public class CompositionController : Controller
{
[HttpGet]
public async Task<string> Get(string transformation = "xml")
{
var httpClient = new HttpClient();
const string authScheme = #"Basic";
const string name = #"myUserName";
const string password = #"myPassword";
var authBytes = Encoding.ASCII.GetBytes($#"{name}:{password}");
var auth64BaseString = Convert.ToBase64String(authBytes);
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authScheme, auth64BaseString);
const string fileName = #"input.xml";
var inputBytes = File.ReadAllBytes(fileName);
var byteArrayContent = new ByteArrayContent(inputBytes);
const string formDataKey = #"""file""";
const string formDataValue = #"""input.xml""";
var multipartFormDataContent = new MultipartFormDataContent()
{
{ byteArrayContent, formDataKey, formDataValue }
};
const string url = #"http://baseurl:port/my/resource/is/there.do?transformation=" + transformation;
var response = await httpClient.PostAsync(url, multipartFormDataContent);
return await response.Content.ReadAsStringAsync();
}
}
You really shouldn't be constructing an HttpClient every time the endpoint is called.
This is what I would do:
//create a service that caches HttpClient based on url
public interface IHttpClientService
{
IHttpClient GetClient(string baseHref);
void AddClient(HttpClient client, string baseHref);
}
//implement your interface
public class HttpClientService : IHttpClientService
{
private readonly ConcurrentDictionary<string, IHttpClient> _httpClients;
public HttpClientService()
{
_httpClients = new ConcurrentDictionary<string, IHttpClient>();
}
public void AddClient(HttpClient client, string baseHref)
{
_httpClients.
.AddOrUpdate(baseHref, client, (key, existingHttpClient) => existingHttpClient);
}
public IHttpClient GetClient(string baseHref)
{
if (_httpClients.TryGetValue(baseHref, out var client))
return client;
return null;
}
}
//register as singleton Startup.cs
services.AddSingleton<IHttpClientService, HttpClientService>();
//inject into Controller
[HttpGet]
public async Task<string> Get(string transformation = "xml")
{
const string url = #"http://baseurl:port/my/resource/is/there.do?transformation=" + transformation;
var httpClient = _httpService.GetClient(url);
if(httpClient == null)
{
httpClient = new HttpClient(url);
const string authScheme = #"Basic";
const string name = #"myUserName";
const string password = #"myPassword";
var authBytes = Encoding.ASCII.GetBytes($#"{name}:{password}");
var auth64BaseString = Convert.ToBase64String(authBytes);
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authScheme, auth64BaseString);
const string fileName = #"input.xml";
var inputBytes = File.ReadAllBytes(fileName);
var byteArrayContent = new ByteArrayContent(inputBytes);
const string formDataKey = #"""file""";
const string formDataValue = #"""input.xml""";
var multipartFormDataContent = new MultipartFormDataContent()
{
{ byteArrayContent, formDataKey, formDataValue }
};
_httpClient.AddClient(httpClient, url);
}
else
{
//You can cache your MultipartFormDataContent in MemoryCache or same cache as HttpClient
//Get MultipartFormDataContent from cache and
}
var response = await httpClient.PostAsync(url, multipartFormDataContent);
return await response.Content.ReadAsStringAsync();
}

How to create role assignments using Azure Active Directory Graph client in C#?

I'm using this library : Microsoft.Azure.ActiveDirectory.GraphClient
class: ActiveDirectoryClient.
I'd like to give an Application (I have the appID) "Owner" access to some subscription. How would I go about doing that? Thanks
The whole premise of this question is incorrect. The GraphClient is not the right client to manage such authorizations. The proper API library for that is Microsoft.Azure.Management.Authorization and the class AuthorizationManagementClient.
I will post additional notes on the actual sequence of calls.
*** Update ***********
As promised here's the sample code:
public static async Task<IServicePrincipal> GetServicePrincipalAsync(string accessToken, string tenantId, string clientId)
{
var graphClient = NewActiveDirectoryClient(accessToken, tenantId);
var matches = await graphClient.ServicePrincipals.Where(sp => sp.AppId == clientId).ExecuteAsync();
return matches.CurrentPage.ToList().FirstOrDefault();
}
private static ActiveDirectoryClient NewActiveDirectoryClient(string accessToken, string tenantId)
{
TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
tcs.SetResult(accessToken);
return new ActiveDirectoryClient(
new Uri($"{GraphApiBaseUrl}{tenantId}"),
async () => { return await tcs.Task; });
}
First you need to get the ObjectId of the principal you want to add. In the case of ServicePricipal I have a function that gets it from the directory like so:
Then using that and a scope ("/subscriptions/{my_subscription_id}", for the entire subscription) you can create a RoleAssignment:
public static async Task AssignRoleToPrincipalAsync(
string accessToken,
string subscriptionId,
string scope,
string roleName,
string principalObjectId)
{
using (var client = NewAuthorizationManagementClient(accessToken, subscriptionId))
{
RoleDefinition roleDef = (await FindRoleDefinitionAsync(accessToken, subscriptionId, scope, roleName)).FirstOrDefault();
if (roleDef == null)
throw new Exception($"Role was not found: {roleName}");
var props = new RoleAssignmentProperties()
{
PrincipalId = principalObjectId,
RoleDefinitionId = roleDef.Id
};
await client.RoleAssignments.CreateAsync(scope, Guid.NewGuid().ToString("N"), props);
}
}
private static AuthorizationManagementClient NewAuthorizationManagementClient(string accessToken, string subscriptionId)
{
return new AuthorizationManagementClient(new TokenCredentials(accessToken)) { SubscriptionId = subscriptionId};
}
***** Update *****
To get the token using Azure.Identity you can use the following snippet
var accessToken = await new AzureCliCredential().GetTokenAsync(
new TokenRequestContext(new[] { "https://management.azure.com/.default" }));
var client = new AuthorizationManagementClient(
new TokenCredentials(accessToken.Token))
{
SubscriptionId = subscription.Data.SubscriptionId
};

Windows 8.1 store app Facebook Integration error

I'm getting following error while integrating facebook api over Windows 8.1 for store apps:-
Given URL is not permitted by application configuration......"
Screenshot showing error dialog:
Please help to resolve this issue.
private FacebookSession _session;
private FacebookClient _client;
private string _accessToken;
string appID = "749110128499368";
Dictionary<string, object> parameters = new Dictionary<string, object>{
{"response_type","token"},
{"display","touch"},
{"redirect_uri","https://www.facebook.com/connect/login_success.html"},
};
FacebookClient oauth;
string[] extended_permissions;
async void getToken()
{
try
{
FacebookSessionClient fbClient = new FacebookSessionClient(appID);
if (ApplicationData.Current.LocalSettings.Values.ContainsKey("fbaccesstoken"))
{
_accessToken = ApplicationData.Current.LocalSettings.Values["fbaccesstoken"].ToString();
}
else
{
_session = await fbClient.LoginAsync("user_about_me,read_stream");
_accessToken = _session.AccessToken;
ApplicationData.Current.LocalSettings.Values["fbaccesstoken"] = _accessToken;
}
_client = new FacebookClient(_accessToken);
}
catch (Exception e){
extended_permissions = new string[] { "user_friends", "email" };
oauth = new FacebookClient() { AppId = appID };
if (extended_permissions != null && extended_permissions.Length > 0)
{
var scope = new StringBuilder();
scope.Append(string.Join(",", extended_permissions));
parameters["scope"] = scope.ToString();
}
getLogin();
}
}
void getLogin()
{
oauth.Version = "2.2";
extended_permissions = new string[] { "user_friends", "email" };
oauth = new FacebookClient() { AppId = appID };
if (extended_permissions != null && extended_permissions.Length > 0)
{
var scope = new StringBuilder();
scope.Append(string.Join(",", extended_permissions));
parameters["scope"] = scope.ToString();
}
var loginUrl = oauth.GetLoginUrl(parameters);
fbBrowser.Navigate(loginUrl);
}
async private void fb_browser_Navigated(object sender, NavigationEventArgs e)
{
FacebookOAuthResult fb_result;
var fb = new FacebookClient();
string uri = e.Uri.AbsoluteUri;
Uri uri_fb = new Uri(uri);
if (fb.TryParseOAuthCallbackUrl(uri_fb, out fb_result))
{
if (fb_result.IsSuccess)
{
_accessToken = fb_result.AccessToken;
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,()=>
{
GetData(_accessToken);
});
}
else
{
var errordescription = fb_result.ErrorDescription;
var errorreason = fb_result.ErrorReason;
MessageDialog m = new MessageDialog(errordescription + "\n" + errorreason);
await m.ShowAsync();
}
}
}
async void GetData(string access_token)
{
string uriString = "https://graph.facebook.com/me?access_token=" + access_token;
HttpClient wClient = new HttpClient();
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,()=>
{
Task gettingData = wClient.GetStringAsync(uriString);
});
}

Categories