Can't catch error from Graph requests (Blazor WASM) - microsoft-graph-api

I am unable to catch errors from when calling the Graph API.
Can anyone explain why I cannot catch the error? Simple example:
#using Microsoft.AspNetCore.Authorization
#using Microsoft.Graph
#attribute [Authorize]
#inject GraphServiceClient GraphClient
#if (allUsers != null)
{
foreach (var user in allUsers)
{
<tr>
<td>#user.DisplayName</td>
<td>#user.Mail</td>
<td>#user.UserPrincipalName</td>
</tr>
}
}
<h2>#errorMessage</h2>
#code {
private string errorMessage = "No errors";
private IEnumerable<Microsoft.Graph.User>? allUsers;
protected override async Task OnInitializedAsync()
{
var queryOptions = new List<QueryOption>
{
new QueryOption("$filter", "userType eq 'member1'") // causes a 400 error since member1 is not valid
};
try
{
//await Task.Delay(10000); // wait 10 seconds
allUsers = await GraphClient.Users.Request(queryOptions).GetAsync();
}
catch (ServiceException ex) // using catch (Exception ex) also doesn't work
{
Console.WriteLine("Error getting users from Graph: " + ex.Message);
Console.WriteLine("Error code: " + ex.Error.Code);
Console.WriteLine("Error inner message: " + ex.Error.InnerError.Message);
// Show error message to the user or log the error
errorMessage = "An error occurred while trying to get users from the Microsoft Graph API.";
}
Console.WriteLine(errorMessage);
}
}
When debugging it just skips over the catch block so it is not being triggered, and no errors are written the console. I know what the error is (using an invalid queryOption), I can see the error details in browser dev tools.

Related

How to get Microsoft 365 Planner 'All Plans for all users' using Microsoft Graph

We have got a requirement to list all Plans for all users along with their respective buckets within the organization.
I tried OAuth authorization services (AAD > App registrations) to access the planner APIs/resources using the Graph API Endpoint however I am getting access denied - It is important to mention here that the app has got all the privileges.
Does Microsoft allow to read all Planners data? provided the account has all the required permissions - if so then what am I missing here?
public static string GetAccessToken_Delegate()
{
try
{
AuthenticationContext authContext = new AuthenticationContext(Globals.AuthorityUrl, true);
AuthenticationResult authResult = authContext.AcquireTokenAsync(Globals.GraphResourceUrl, Globals.AppId, new Uri(Globals.RedirectUri), new PlatformParameters(PromptBehavior.Auto)).Result;
return authResult.AccessToken;
}
catch (Exception ex)
{
WriteLogEvents.WriteException(ex);
}
return null;
}
public static GraphServiceClient GetGraphClient(string graphToken)
{
try
{
DelegateAuthenticationProvider authenticationProvider = new DelegateAuthenticationProvider(
(requestMessage) =>
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", graphToken);
return Task.FromResult(0);
});
return new GraphServiceClient(authenticationProvider);
}
catch (Exception ex)
{
WriteLogEvents.WriteException(ex);
}
return null;
}
public async static Task<List<PlansData>> GetPlans()
{
List<PlansData> plansData = new List<PlansData>();
try
{
String accessToken = GetAccessToken_Delegate();
GraphServiceClient graphClient = GetGraphClient(accessToken);
if (graphClient != null)
{
message += string.Format("GraphClient Base Url: {0}", graphClient.BaseUrl) + Environment.NewLine;
plansData = await GetGroup(graphClient, plansData);
}
else
throw new Exception("GraphServiceClient is null");
}
catch (Exception ex)
{
WriteLogEvents.WriteException(ex);
}
finally
{
}
return plansData;
}
public async static Task<List<PlansData>> GetGroup(GraphServiceClient graphClient, List<PlansData> plansData)
{
try
{
IGraphServiceGroupsCollectionPage groupCollection = await graphClient.Groups.Request().GetAsync();
if (groupCollection?.Count > 0)
{
message += string.Format("Group Count: {0}", groupCollection.Count) + Environment.NewLine;
foreach (Microsoft.Graph.Group group in groupCollection)
{
if (group is Microsoft.Graph.Group)
{
if (group != null && group.GroupTypes != null && group.GroupTypes.Count() > 0)
{
plansData = await GetPlanData(graphClient, plansData, group);
}
}
}
}
}
catch (Exception ex)
{
WriteLogEvents.WriteException(ex);
}
return plansData;
}
public async static Task<List<PlansData>> GetPlanData(GraphServiceClient graphClient, List<PlansData> plansData, Microsoft.Graph.Group group)
{
try
{
//https://graph.microsoft.com/v1.0/groups/a047a2b3-3687-4464-bbdb-084f675c7528/planner/plans
//Get Plans Information based on the group id
IPlannerGroupPlansCollectionPage plansCollection = await graphClient.Groups[group.Id].Planner.Plans.Request().GetAsync();
if (plansCollection?.Count > 0)
{
message += string.Format("Plans Count: {0}", plansCollection.Count) + Environment.NewLine;
foreach (PlannerPlan record in plansCollection)
{
List<Bucket> bucketsList = await GetBuckets(graphClient, record.Id);
Groups groupData = new Groups(group.Id, group.DisplayName);
string siteUrl = string.Format("https://myOrg.sharepoint.com/teams/{0}/", group.MailNickname);
plansData.Add(new PlansData(record.Id, record.Title, siteUrl, groupData, bucketsList));
}
}
}
catch (Exception ex)
{
WriteLogEvents.WriteException(ex);
}
return plansData;
}
public async static Task<List<Bucket>> GetBuckets(GraphServiceClient graphClient, string planId)
{
List<Bucket> bucketsList = new List<Bucket>();
try
{
//https://graph.microsoft.com/v1.0/planner/plans/CONGZUWfGUu4msTgNP66e2UAAySi/buckets
//Get Plans Information based on the group id
IPlannerPlanBucketsCollectionPage bucketCollection = await graphClient.Planner.Plans[planId].Buckets.Request().GetAsync();
if (bucketCollection?.Count > 0)
{
message += string.Format("Buckets Count: {0}", bucketCollection.Count) + Environment.NewLine;
foreach (PlannerBucket bucket in bucketCollection)
{
Bucket b = new Bucket(bucket.Id, bucket.Name);
bucketsList.Add(b);
}
}
}
catch (Exception ex)
{
WriteLogEvents.WriteException(ex);
}
return bucketsList;
}
Thanks in advance.
You can now use application permissions to read the data.
Outdated Reply:
Planner does not support Application permissions yet. Exporting all
plan data is possible with a non-graph API and requires a delegated
access token for tenant admin. We're working on the documentation for
this and making it available from graph as well.

WepApi TaskCanceledException A task was canceled. httpClient

It was working good, but I made some changes in the api, adding more controllers nothing out of the place, and then it stops working, always thrown an exception: "TaskCanceledException: A task was canceled" in the line GetAsync().result. I increase the timeout and infinitely stays loading.
The code controller APP who make a request to the controller API:
public ActionResult Login(LoginM us)
{
try
{
cuentaM account = new cuentaM();
HttpClient client = new HttpClient();
var result = client.GetAsync("http://localhost:26723/api/Login" + "?email=" + us.email + "&password=" + us.password).Result;
if (result.IsSuccessStatusCode)
{
account = result.Content.ReadAsAsync<cuentaM>().Result;
}
Session["cuenta"] = account;
return RedirectToAction("Index", "Home");
}
catch (Exception ex)
{
throw;
}
}
The controller API code:
public HttpResponseMessage Get(string email, string password)
{
try
{
using (elevationbEntities db = new elevationbEntities())
{
usuario user = db.usuarios.Where(m => m.email == email && m.password == password).SingleOrDefault();
cuentaM account = new cuentaM();
if (user != null)
{
account = (from o in db.cuentas
join cu in db.cuentausuarios on o.idCuenta equals cu.idCuenta
join u in db.usuarios on cu.idUsuario equals u.idUsuario
where u.idUsuario == user.idUsuario
select new cuentaM { idUsuario = user.idUsuario, idCuenta = o.idCuenta, CodigoUnico = o.CodigoUnico })
.FirstOrDefault();
}
else
{
account.Error = "Wrong Password or Email";
}
HttpResponseMessage response;
response = Request.CreateResponse(HttpStatusCode.OK, account);
return response;
}
}
catch (TaskCanceledException ex)
{
HttpResponseMessage response;
response = Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
return response;
}
}
Making blocking calls (.Result) on HttpClinet's async API can cause deadlocks especially if being used asp.net MVC, which may have async operations being invoked when the blocking call was made.
Make the code async all the way through.
Also try to avoid creating an instance of HttpClient on every request. This can cause sockets to be exhausted.
private static HttpClient client = new HttpClient();
public async Task<ActionResult> Login(LoginM us) {
try {
cuentaM account = new cuentaM();
var url = "http://localhost:26723/api/Login" + "?email=" + us.email + "&password=" + us.password
var result = await client.GetAsync(url);
if (result.IsSuccessStatusCode) {
account = await result.Content.ReadAsAsync<cuentaM>();
}
Session["cuenta"] = account;
return RedirectToAction("Index", "Home");
} catch (Exception ex) {
throw;
}
}
You may be deadlocking by blocking on an async call, as described in this article. Here's the problematic line:
account = result.Content.ReadAsAsync<cuentaM>().Result;
Change the method signature for Login to:
public async Task<ActionResult> Login(LoginM us)
Then change the problematic line to use await instead of .Result:
account = await result.Content.ReadAsAsync<cuentaM>();

An asynchronous module or handler completed while an asynchronous operation was still pending

Description :
I'm sending an email from MVC application, mail was sent successfuly when I send it to a single person but when I send mail to multiple people then getting an exception i.e. Operation has timed out.
So, to avoid this problem I'm trying use smtpclient.SendAsync(message,object) method but I'm getting an exception i.e. An asynchronous module or handler completed while an asynchronous operation was still pending.
How to resolve this problem ?
Code:
public async Task<string> SendEmail(List<string> ToEmailAddresses,string body, string emailSubject)
{
var smtp = new SmtpClient
{
DeliveryMethod = SmtpDeliveryMethod.Network,
Host = "xyz-host-name",
Port = 25,
EnableSsl = false,
Timeout = 600000
};
var fromAddress = new MailAddress(ConfigurationManager.AppSettings["MailUserName"], "Rewards and Recognition Team");
using (var message = new MailMessage() { Subject = emailSubject, Body = body })
{
message.From = fromAddress;
foreach (string email in ToEmailAddresses)
{
message.To.Add(email);
}
message.IsBodyHtml = true;
try
{
_logger.Log("EmailService-SendEmail-try");
object userToken = message;
smtp.SendAsync(message,userToken);
return "Success";
}
catch (Exception ex)
{
_logger.Log("EmailService-SendEmail-" + ex.Message);
return "Error";
}
}
}
you have to use the await keyword in actionresult (controller side)
like
public async task<ActionResult> SendMail(object obj)
{
var result = await SendEmail(ToEmailAddresses,body,emailSubject)
return result
}

SendAsync always showing Status Waiting using MVCmailer

I am developing application in MVC5 and MVCMailer. I am sending email using SendAsync command which always show Status = "WaitingforResponse" and mail is not sent. If I use "Send" command instead, it works fine. Here is my code:
var v = new UserMailer().SendCampaignMail("email_address").SendAsync();
and UserMailer.cs
public virtual MvcMailMessage SendCampaignMail(string Email)
{
try
{
return Populate(x =>
{
x.Subject = "Campaing";
x.ViewName = "PasswordReset";
x.To.Add(Email);
});
}
catch(Exception ex)
{
throw ex;
}
}
Screenshot for response: http://prntscr.com/82yfwq
Thanks for your Help:

NLog use in MVC application

How can I use NLog to get detail information regarding a local error?
Until now I have this:
private static Logger logger = LogManager.GetCurrentClassLogger();
public ActionResult Index()
{
try
{
var domain = db.Works.ToList();
var model = Mapper.Map<IList<Work>, IList<WorkIndexViewModels>>(domain);
return View(model);
}
catch (Exception e)
{
logger.Error("Error in Index: " + e);
}
}
If I put the return after the catch, the model is out of scope.
If I put the return inside the try, I get "not all code path returns a value" from the Action.
So how can I solve this?
Since you've already captured the error and you can't show the requested page, you could redirect within the catch to your error page:
catch (Exception e)
{
logger.Error("Error in Index: " + e);
return RedirectToAction("Index", "Error"); // Redirect to error controller or page
}
Alternatively, and probably more appropriate, you could have your action raise a 500 error so that your error configuration within your web.config can properly handle redirection.
catch (Exception e)
{
logger.Error("Error in Index: " + e);
return new HttpStatusCodeResult(500); // Raise internal server error
}

Resources