I'm trying to implement a custom error handling in web API,
and I need to get the exception from the returned HttpResponseMessage.
I've tried to get exception info by from:
response.Content.ReadAsAsync<HttpError>().Result
But I can't access the result object, I'm getting an exception when trying,
So I'm obviously doing it wrong.
Can't figure out how to do it,
Assistance would be appreciated.
Edit:
My client code is not relevant, it's simply a GET request, server code:
Controller action throws Exception:
if (condition == true)
{
var response = new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = new StringContent("Some Exception Related Message"),
ReasonPhrase = "Some More Info"
};
throw new HttpResponseException(response);
}
SendAsync method of my implemented DelegatingHandler gets the response,
and this is where I want to get the callstack of the exception that was thrown in the controller action above.
errorDetails = new ResponseErrorDetailsFull
{
Message = "An error has occurred.",
ExceptionMessage = response.ReasonPhrase,
StackTrace = response.Content.ReadAsAsync<HttpError>().Result.StackTrace
};
Edit #2
Ok, So I found out that if I create a ExceptionFilterAttribute, and Override OnException(), use the attribute on my DelegatingHandler I'm able to access the exception as mentioned in the above code.
Can someone provide an explanation why this is working this way?
To get HttpError in the response content, your server side API code needs to have written an HttpError instance into the response stream.
Only then response.Content.ReadAsAsync<HttpError>().Result would yield that data.
normally, if a server side code throws an exception, the default behavior is an HTTP 500 (Internal Server Error) status code with nothing parseable in the response message.
In case of HTTP 400 (Bad Request) or other such non-500 (non-200) errors, it is customary to send back response data. (either Validation Errors etc.)
in that case, you may be able to read the data from the response.
in general for any error scenario, unless your server side API code is not writing a known type into the response, you cannot read it off the response on the caller side.
please post your server side and client side code, for us to help you further.
I found this blog with very good example:
http://nodogmablog.bryanhogan.net/2016/07/getting-web-api-exception-details-from-a-httpresponsemessage/
I adopted the code with some updates:
if ((int)response.StatusCode >= 400)
{
exceptionResponse = JsonConvert.DeserializeObject<ExceptionResponse>(LogRequisicao.CorpoResposta);
LogRequisicao.CorpoResposta = exceptionResponse.ToString() ;
if (exceptionResponse.InnerException != null)
LogRequisicao.CorpoResposta += "\r\n InnerException: " + exceptionResponse.ToString();
}
using object:
public class ExceptionResponse
{
public string Message { get; set; }
public string ExceptionMessage { get; set; }
public string ExceptionType { get; set; }
public string StackTrace { get; set; }
public ExceptionResponse InnerException { get; set; }
public override String ToString()
{
return "Message: " + Message + "\r\n "
+ "ExceptionMessage: " + ExceptionMessage + "\r\n "
+ "ExceptionType: " + ExceptionType + " \r\n "
+ "StackTrace: " + StackTrace + " \r\n ";
}
}
Related
I'm trying to read the messages from the Google API but when I check the Payload.Body.Data to see the content of the email always comes null.
But when I use Raw format I see the body but it's a little complicated to handle the information because it's in a huge and dirty string.
public static Message GetMessage(GmailService service, String userId, String messageId)
{
try
{
var request = service.Users.Messages.Get(userId, messageId);
request.Format = Google.Apis.Gmail.v1.UsersResource.MessagesResource.GetRequest.FormatEnum.Full;
var message = request.Execute();
return message;
}
catch (Exception e)
{
Console.WriteLine("An error occurred: " + e.Message);
}
return null;
}
Below is my code for both methods -
GatherCall is returning Twiml still I get HTTP 415 & same for StatusCallback method. Can someone please help here? I am not even able to test this using ngrok as Tunneling tools don't work in my organisation network. I am using Azure to test this one by logging everything.
public TwiMLResult GatherCall([FromRoute] string id, [FromBody] VoiceRequest voiceRequest )
{
_logger.LogInformation("*****************GatherCall - Start****************");
var response = new VoiceResponse();
try
{
_logger.LogInformation("Gather call back for -" + id);
_logger.LogInformation("VoiceRequest parameters-------------------------");
_logger.LogInformation("CallSid : " + voiceRequest.CallSid);
_logger.LogInformation("CallStatus : " + voiceRequest.CallStatus);
_logger.LogInformation("AccountSid : " + voiceRequest.AccountSid);
_logger.LogInformation("From : " + voiceRequest.From);
_logger.LogInformation("To : " + voiceRequest.To);
_logger.LogInformation("Digits : " + voiceRequest.Digits);
_logger.LogInformation("Direction : " + voiceRequest.Direction);
_logger.LogInformation("TranscriptionText : " + voiceRequest.TranscriptionText);
if (voiceRequest.Digits == "1234")
{
response.Say("Your response has been recorded. Thank you.", voice: "alice");
response.Hangup();
//acctepted response
//update call status to db
//acknowledge incident
}
else
{
response.Say("Incorrect code enterted. Please enter correct code to accespt this incident", voice: "alice");
response.Pause(3);
response.Hangup();
}
_logger.LogInformation("*****************GatherCall - EndTry****************");
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
_logger.LogInformation("*****************GatherCall - EndCatch****************");
}
return TwiML(response);
// return TwiML(response.ToString(), "application/xml");
}
public IActionResult StatusCallBack([FromRoute] string id, [FromBody] StatusCallbackRequest statusCallbackRequest)
{
_logger.LogInformation("*****************StatusCallBack - Start****************");
try
{
_logger.LogInformation("Status call back called for -" + id );
_logger.LogInformation("StatusCallbackRequest parameters-------------------------");
_logger.LogInformation("CallSid : " + statusCallbackRequest.CallSid);
_logger.LogInformation("CallStatus : " + statusCallbackRequest.CallStatus);
_logger.LogInformation("AccountSid : " + statusCallbackRequest.AccountSid);
_logger.LogInformation("From : " + statusCallbackRequest.From);
_logger.LogInformation("To : " + statusCallbackRequest.To);
_logger.LogInformation("Digits : " + statusCallbackRequest.Digits);
_logger.LogInformation("Direction : " + statusCallbackRequest.Direction);
_logger.LogInformation("TranscriptionText : " + statusCallbackRequest.TranscriptionText);
_logger.LogInformation("*****************StatusCallBack - EndTry****************");
return Ok("Handled");
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
_logger.LogInformation("*****************StatusCallBack - EndCatch****************");
return Ok("Handled in catch");
}
}
Twilio Evangelist here... Sorry that you're having a tough time. It looks like your code is trying to bind the voiceRequest parameter to the body of the incoming POST request from Twilio (using [FromBody]). If Twilio is sending a POST request, you'll want to bind to the form (using [FromForm]). Otherwise, ASP.NET Core will return a 415 error code.
Try swapping out the [FromBody] with a [FromForm]. That should fix this on a POST request. I would also suggest verifying that Twilio is in fact sending a POST, not a GET request.
If you run into more problems, send a note across via email to corey#twilio.com. Hope this helps.
I need to return the server error from azure functions.
Now I implement the same using InternalServerErrorResult(). It only sends the error code and no response/message can be sent with this function.
How to implement an exception handler where the error code and message can be sent together using actionresult in azure functions
current implementation
catch (Exception ex)
{
log.LogInformation("An error occured {0}" + ex);
//json = new Response(ex.StackTrace, AppConstants.ErrorCodes.SystemException).SerializeToString();
return (ActionResult)new InternalServerErrorResult();
}
this returns with an empty response in postman with error 500
Note that this is from Microsoft.AspNetCore.Mvc namespace:
var result = new ObjectResult(new { error = "your error message here" })
{
StatusCode = 500
};
Based on configured formatters it will return serialized object to client.
For JSON (it's default) it will return following:
{ "error" : "your error message here" }
To send a message with the status code you can use return StatusCode(httpCode, message), which is an ObjectResult.
For example:
return StatusCode(500, "An error occurred");
You can also pass an object (example using HttpStatusCode enum):
return StatusCode((int)HttpStatusCode.InternalServerError, json);
I have method where it takes some parameter and the response is in json format.
On success it will return int type value.
But if error occurs then rest service will throw exception where as the method which is implements the REST service must return int value.
internal static int AddCatalog(string name, Guid key, string userName)
{
using (var client = new HttpClient())
{
HttpResponseMessage response = client.PutAsync(AdminRestServiceUrl + "xml/updatecatalog?cid=" + null + "&name=" + name + "&key=" + key + "&uby=" + userName, null).Result;
response.EnsureSuccessStatusCode();
var cid= response.Content.ReadAsStringAsync().Result;
return Convert.ToInt32(cid);
}
}
How can I handle it effieciently, if service throws error?
if i do like this
if(response.IsSuccessStatusCode == HttpStatusCode.OK)
{
return convert.ToInt32(cid);
}
else
{
return ?? //how to handle error here as method must retun int type
}
Please suggest how should I pass the detailed error message to the clients in order to notify them the exact error occurred in the service.
Any kind of help/suggestion is greatly appreciated.
you can do possibly Make an "ErrorLogs" Class ,Keep "Status" Field in it , and the Error Exception in "Message" Field , if there occurs any error send status to failed
In both Cases return a Class Which has both Error Logs and and Integer Value, if there is error Return Integer as -1 and handle it on Client
My sample code of ApiKey validation is given below (I am using MVC4 web api RC):
public class ApiKeyFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext context)
{
//read api key from query string
string querystring = context.Request.RequestUri.Query;
string apikey = HttpUtility.ParseQueryString(querystring).Get("apikey");
//if no api key supplied, send out validation message
if (string.IsNullOrWhiteSpace(apikey))
{
var response = context.Request.CreateResponse(HttpStatusCode.Unauthorized, new Error { Message = "You can't use the API without the key." });
throw new HttpResponseException(response);
}
else
{
try
{
GetUser(decodedString); //error occurred here
}
catch (Exception)
{
var response = context.Request.CreateResponse(HttpStatusCode.Unauthorized, new Error { Message = "User with api key is not valid" });
throw new HttpResponseException(response);
}
}
}
}
Here problem is with Catch block statement. I Just wanted to send custom error message to user. But nothing is sent. It displays a blank screen
However, the statement below is working well and sends out the validation error message correctly:
if (string.IsNullOrWhiteSpace(apikey))
{
var response = context.Request.CreateResponse(HttpStatusCode.Unauthorized, new Error { Message = "You can't use the API without the key." });
throw new HttpResponseException(response);
}
Is there anything that i am doing wrong.
I was having the same issue in the exact same scenario. However, in this scenario, you need to return some content in your response to be shown and not really throw the exception. So based on this, I would change your code to the following:
catch (Exception)
{
var response = context.Request.CreateResponse(httpStatusCode.Unauthorized);
response.Content = new StringContent("User with api key is not valid");
context.Response = response;
}
So with this change you are now returning your response, with content that will displayed in place of the blank screen.