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.
Related
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);
}
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'm working on an API with .Net Core 2.1 Framework and I faced a pretty strange problem.
In my controller when I catch some specific exceptions I return either a BadRequest or NotFound in which I pass the error message as a parameter.
Controller Action:
[HttpPost]
public async Task<ActionResult<ApiViewModel>> DoStuffAsync([FromBody] ApiCommand command)
{
if (command == null || !ModelState.IsValid)
{
return BadRequest();
}
try
{
// some code
return Ok(ApiViewModel);
}
catch (InvalidStuffException ex)
{
_logger.LogError(ex, LogErrorMethodMessage);
return BadRequest(ex.Message);
}
catch (Exception ex)
{
_logger.LogError(ex, LogErrorMessage);
return NotFound(ex.Message);
}
}
The thing is even though BadRequest should be returning my error message with a status code of 400 it actually returns 201. Same thing for NotFound.
I have no idea why this's happening,and I also would like to add the fact that when I return BadRequest without passing any parameter to it the status code returned is the correct one => 400.
When i catch the exception and do the following:
catch (InvalidStuffException ex)
{
_logger.LogError(ex, LogErrorMethodMessage);
return BadRequest();
}
Here's what i get as a result : Empty message with status code 400
But if i passed a message in the BadRequest like the following:
catch (InvalidStuffException ex)
{
_logger.LogError(ex, LogErrorMethodMessage);
return BadRequest(ex.Message);
}
I get ma message but with status code 201:
Can anybody please explain to me the reason behind this?
Thank you very much.
Up to now if a web api 2 error happened and I caught it, I'd return a custom object and fill in the error message from the catch. This would however make the actually http.post() go into success method instead of the error and then I'd have to look at my own boolean success variable and if true all good, if false show error. This is kind of annoying as I have to look for errors in 2 different places for 2 different reasons. From Web API 2 is there a way I can make the http.post() trigger the error callback while I fill out the error message if I catch an error in the web api controller?
[HttpPost]
public MyResponseObject UpdateData(RequestObject req)
{
MyResponseObject resp = new MyResponseObject();
resp.Success = true;
try{
// error happens here
}catch(Exception ex){
resp.Success = false;
resp.Msg = ex.Message;
}
return resp;
}
The http.post() call will still be successful but now I have to look in the success callback for my resp.Success to see if it was REALLY successful or not. Sure the API call was able to be made, but something went wrong inside of it. I'd like to just be able to display that message and fail the call so the http.post() error callback is called with the exception message.
Just throw an exception:
throw new HttpResponseException(HttpStatusCode.InternalServerError);
If you want to customize the response that is returned you can create a HttpResponseMessage with more detail:
var response = new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = new StringContent("We messed up"),
ReasonPhrase = "Error"
}
throw new HttpResponseException(resp);
Documentation here