i am using below code to send email using microsoft graph
await graphClient.Me.SendMail(message, true).Request().PostAsync()
Since post operation doesnt return anything then how to detect status code 429 (Throttle response code)and handle it.
PostAsync() method should throw a ServiceException on error. For example:
try
{
await graphClient.Users[userId].SendMail(message).Request().PostAsync();
}
catch (Microsoft.Graph.ServiceException e)
{
Console.WriteLine(e.Error);
}
Related
So, guys I have a route in my API that receives a JSON than it is treated and sended back.
What is wrong with that? Nothing.
But has a strange behavior that sometimes I send a json document and receive error 500 with the message "An unxpected erro occurred" but If I send it again (without change nothing) then it works;
Please guys, can you help me telling me how can I catch an exception for this, if there is one.
This is the code that receives the request:
public async Task<string> SaveHumanChat(JObject talk)
{
if (!ModelState.IsValid)
return BadRequest(ModelState).ToString();
var conversa = talk.ToString();
try
{
return await _service.SaveHumanChat(conversa);
}
catch (Exception e)
{
return e.Message;
}
}
Ps: I've tried to use ArgumentException but without success.
I'm working on a Core 3.1 Web API and an MVC application that uses it. In the MVC app I have UserRepo set up containing an Update method:
public async Task<User> Update(User user)
{
HttpClient client = _clientFactory.CreateClient("namedClient");
HttpResponseMessage response = await client.PutAsync($"api/Users/{user.Id}", ContentEncoder.Encode(user));
try
{
response.EnsureSuccessStatusCode();
}
catch (Exception ex)
{
if ((int)response.StatusCode == StatusCodes.Status409Conflict)
{
throw;
}
}
return await response.Content.ReadFromJsonAsync<User>();
}
The repo is injected into a service, and the service is injected into a controller which is where I'd like to handle the error.
The Update method is incomplete because I am trying to figure out how handle a 409 error which I return from API if the rowversion value was outdated. When response.EnsureSuccessStatusCode(); is called, an exception is thrown if it wasn't a success code. I imagined I could just have it bubble-up to the front-end and handle it in the controller action, but the exception object doesn't contain anything specific enough to identify that it's a 409 error:
So if this bubbles up to the controller action, best I could to is try to parse out the status code from the message, which seems like a bad idea.
I can find examples of people returning 409 codes from their Web APIs, but not how they would be handled in an MVC app when logic is separated into different classes instead of being all in one action.
How could I handle this? Do I create a custom exception and throw that? Maybe add additional data to the exception with ex.Data.Add() and read it in the action? Would that be a bad idea?
Thanks to suggestions from #Peter Csala, #Craig H, and #Filipe, this is the solution I settled on.
Method that calls the API:
public async Task<User> Update(User user)
{
HttpClient client = _clientFactory.CreateClient("namedClient");
HttpResponseMessage response = await client.PutAsync($"api/Users/{user.Id}", ContentEncoder.Encode(user));
await HttpResponseValidator.ValidateStatusCode(response);
return await response.Content.ReadFromJsonAsync<User>();
}
A static method I can reuse that will produce an exception during a concurrency error:
public static class HttpResponseValidator
{
public static async Task ValidateStatusCode(HttpResponseMessage response)
{
if ((int)response.StatusCode < 200 || (int)response.StatusCode > 299)
{
string errorResponse = await response.Content.ReadAsStringAsync();
if (response.StatusCode == HttpStatusCode.Conflict)
{
DBConcurrencyException ex = new DBConcurrencyException(errorResponse);
throw ex;
}
}
}
}
The exception bubbles up all the way back to the action that called the method calling the API. I catch it in the action and handle it after logging the error.
I'm working on a Core 3.1 Web API and an MVC application that uses it. In the MVC app I have UserRepo set up containing methods that send requests to the API:
public class UserRepo : IUserRepo
{
private readonly IHttpClientFactory _clientFactory;
public UserRepo(IHttpClientFactory httpClientFactory)
{
_clientFactory = httpClientFactory;
}
public async Task<User> GetById(int Id)
{
// same code structure as Update ...
}
public async Task<User> Update(User user)
{
HttpClient client = _clientFactory.CreateClient("NamedClient");
try
{
HttpResponseMessage response = await client.PutAsync($"api/Users/{user.Id}", ContentEncoder.Encode(user));
return await response.Content.ReadFromJsonAsync<User>();
}
catch (Exception ex)
{
throw;
}
}
public async Task<User> Insert(User user)
{
// same code structure as Update ...
}
}
The Update method never throws errors like 400, 404, etc, that come back from the API, resulting in silent errors. I found that to cause exceptions I need to call response.EnsureSuccessStatusCode();, which worked.
However, the exception doesn't contain what I need to find out what went wrong with the API call. If a 400 error occurs, an exception will be thrown saying that 400 error occurred, but not why it occurred. The why is returned to the response variable and it may look something like this due to validation I have implemented:
{
"errors": {
"FirstName": [
"The FirstName field is required."
]
},
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "|502d647b-4c7425oa321c8c7b."
}
Is there a widely used way to handle the response that comes back after an error is produced in the API? I want to know why a 400 error occurred so I know what to fix. I just don't know what is the "right" way to handle these response messages.
One idea I had was to catch the exception and log it along with the response text every time before throwing it. Then when my app crashes I can go to the logs and read the message returned. The Update method would look like this:
public async Task<User> Update(User user)
{
HttpClient client = _clientFactory.CreateClient("NamedClient");
HttpResponseMessage response = await client.PutAsync($"api/Users/{user.Id}", ContentEncoder.Encode(user));
try
{
response.EnsureSuccessStatusCode();
}
catch (Exception ex)
{
string errorMessage = await response.Content.ReadAsStringAsync()
_logger.LogError(ex, errorMessage);
throw;
}
return await response.Content.ReadFromJsonAsync<User>();
}
Another thought that came would be maybe it's possible to add the message to the exception itself and see it when it's thrown? Would it make sense to add the message as an inner exception?
Is there a widely used way to handle the response that comes back after an error is produced in the API? I want to know why a 400 error occurred so I know what to fix. I just don't know what is the "right" way to handle these response messages.
Generally, exception details are only logged, and not returned. This is because details may include personally identifiable information or technical details that could reveal potential security vulnerabilities. There is an error details RFC that is becoming more common, but even that should not have details like PII or a stack trace.
In the case of one API (the MVC endpoint) calling another API (the actual API), the MVC endpoint should return a code in the 5xx range. Either 500 or 502 would be acceptable here. All such errors should be logged on the server side along with their details.
Note that the default behavior is to return 500 if an exception is propagated, so keeping the throw; is all you really need to do. However, it's normal to do error logging in the "pipeline", e.g., middleware for ASP.NET Core or something like a globally-installed action filter for ASP.NET MVC. This is to ensure all errors are logged while avoiding repetition.
EnsureSuccessStatusCode throws an HttpRequestException if the StatusCode is different than 2xx.
In order to gain the most information from the response, you have to retrieve it manually.
The general flow could be described in the following way:
Issue the request inside a try-catch block.
If there was no exception then examine the response's statusCode.
If it is different than the expected one(s) then try to read the response's body
And log everything.
Step #1
HttpResponseMessage response = null;
try
{
response = await httpClient.PutAsync(...);
}
catch (InvalidOperationException ioEx)
{
//The request message was already sent by the HttpClient instance, but failed due to some protocol violation
HttpClient.CancelPendingRequests();
//TODO: logging
}
catch (TaskCanceledException tcEX)
{
//The request was not completed due to either it's timed out or cancelled
if(!tcEX.CancellationToken.IsCancellationRequested)
HttpClient.CancelPendingRequests();
//TODO: logging
}
catch (HttpRequestException hrEx)
{
//The request failed due to an underlying issue such as network connectivity, DNS failure, server certificate validation.
//TODO: logging
}
Step #2
HttpStatusCodes[] validResponseCodes = new [] {
HttpStatusCode.OK,
HttpStatusCode.Created,
HttpStatusCode.NoContent,
};
if(!validResponseCodes.Contains(response?.StatusCode))
{
//Step #3
}
Step #3
string errorResponse = await response.Content.ReadAsStringAsync();
//Try to parse it if you know the structure of the returned json/xml/whatever
I am using Flurl Client to call a restful API with a post data. There is a validation performed on the server on the data I submit and it returns back a header containing an error message for the user.
As the request requirement doesn't satisfy server marks the request as 400 BadRequest. In the below code on line cli.Request(uri).PostJsonAsync(data) it throws the FlurlHttpException with appropriate status code.
Now, as there is a problem with the input data by the user I want to report the user back with the error message which I receive from the server in the header. However, I am unable to access the response headers as the request has failed.
Is there any other way to access the response headers from a failed request using Flurl?
try
{
using (var cli = new FlurlClient(baseUrl))
{
var httpResponse = await cli.Request(uri).PostJsonAsync(data);
var errorMessage = httpResponse.GetHeaderValue("errorMessage");
}
}
catch (FlurlHttpException ex)
{
}
Using an event handler works, but I think those are better for cross-cutting concerns like logging that you don't want cluttering the main flow of your app. You basically want to allow and/or handle 400 responses as part of that main flow. You can do that more directly with AllowHtttpStatus, which can be set on the client:
cli.AllowHtttpStatus(HttpStatusCode.BadRequest);
or the request:
var httpResponse = await cli
.Request(uri)
.AllowHttpStatus(HttpStatusCode.BadRequest)
.PostJsonAsync(data);
Either way, the call will not throw on a 400.
Another way to do this, and one I'd recommend if your app logic takes a completely different path on an error condition than on a success condition, is to keep your try/catch in place and use the Response property of the exception to handle the error condition:
try
{
await cli.Request(uri).PostJsonAsync(data);
// handle success condition
}
catch (FlurlHttpException ex) when (ex.Response?.StatusCode == 400)
{
var errorMessage = ex.Response.GetHeaderValue("errorMessage");
// handle error condition
}
As a side note, there are some significant changes coming in 3.0 that you should be aware of as they touch on some of these areas directly:
https://github.com/tmenier/Flurl/issues/354
https://github.com/tmenier/Flurl/issues/488
I am configuring the Error Event Handler to report any error. As a result, the code doesn't jump to the exception block it asynchronously fires the event handler, and the rest of my subsequent code executes OK with an appropriate httpResponseMessage, StatusCode, headers everything.
...
FlurlHttp.Configure(settings => settings.OnErrorAsync = HandleFlurlErrorAsync);
using (var cli = new FlurlClient(baseUrl))
{
var httpResponse = await cli.Request(uri).PostJsonAsync(data);
var errorMessage = httpResponse.GetHeaderValue("errorMessage");
}
...
private async Task HandleFlurlErrorAsync(HttpCall call)
{
//Log your exception here
call.ExceptionHandled = true;
}
Using C#/Asp.Net
I have an application that goes out to a web service. On return there's a couple of things that happen:
void Cleanup(Response response)
{
// My web service takes up to 30 seconds
// then this method is called
// I send this email
var email = SaleEmail.Create(
response.ID
DateTime.Now,
"A sale was made!");
email.Send();
// Then redirect
Response.Redirect(response.RedirectUrl, false);
Context.ApplicationInstance.CompleteRequest();
}
The idea is, on completion of the web service an email is sent, then the page is redirected.
Previously, I used a normal redirect - the result was that 90% of the emails were never sent.
I've changed the redirect pattern, however it's still not perfect - I'm guessing 25% of emails are still not coming through.
Anyone advise any improvements to the pattern I have?
Email code:
public static void Send(MailMessage message)
{
Guard.Argument.NotNull(() => message);
var c = new SmtpClient();
try
{
c.Send(message);
}
catch (Exception ex)
{
}
finally
{
c.Dispose();
message.Dispose();
}
}
Maybe
Try to implement async task method with sendAsync and await
this await will help you to wait how much needed to send email before jump to redirect
//async Task
public async Task Cleanup(Response response)
{
using (var smtpClient = new SmtpClient())
{
await smtpClient.SendAsync();...//await
}
}
you should rewrite your initialization somehow, make it look like this:
smtpClient.SendAsync();
smtpClient.SendCompleted += new SendCompletedEventHandler(smtpClient_SendCompleted);
on smtpClient_SendCompleted function write your redirection code