I created an ASP.NET Core Web API. I throw own error with some text and try to get this text in my client. When I do it locally, it works. But when I hosted it in Azure, it does not work - I just get a 500 error.
This is in my controller:
catch (LoginException ex)
{
throw new LoginException(ex.Message);
}
This is how I throw my error
if (GetPerson(person.NickName))
throw new LoginException("Text");
Is is my error:
public class LoginException:Exception
{
public LoginException(string message) : base(message)
{
}
}
Often 500 error - is a backend problem error. It is better to throw your exception in another class (an example, LoginService) and catch it in your controller. Then you must not throw an exception in controller, but send normal response like return BadRequest(ex.message).
I have some rest API written in C# and the API is called from Angular (I am using version Angular 8). The call is fine and it is working fine. However, in case of any exception, I cannot display the customized error message in angular. For example, suppose I have a server side validation in C# which validates if the value of a field matches with the string "abc". If it does not match, it will throw an error and in UI (developed in Angular), I want to display the message
"Invalid String Specified".
My server side code is as below -
if (headerValues.Equals("abc")) {
throw new InvalidStringException("Invalid String specified", 999);
}
The Invalid InvalidStringException class is as below -
public class InvalidStringException : System.Exception
{
int status { get; set; }
public InvalidStringException() { }
public InvalidStringException(string message, int status) : base(message) {
this.status = status;
}
}
When that exception is thrown and caught in server side, it is available as 500 exception but could not print the custom message.
I am trying following code in Angular -
} catch (error) {
console.log("Error Status: ", error.status);
console.log("Error Status: ", error.message);
}
Please suggest how to handle that scenario.
The error object that your Angular app receives should be an instance of HttpErrorResponse
You could do something like this to handle http errors:
if (error instanceof HttpErrorResponse) {
if (!error.status) {
console.log(error.message || error.toString());
} else {
console.log(`error status : ${error.status} ${error.statusText}`);
switch (error.status) {
case 401:
this.router.navigateByUrl("/login");
break;
case 500:
this.router.navigateByUrl("/login");
console.log(`redirect to login`);
break;
}
}
} else {
console.error("Other Errors");
}
You are throwing an exception which is handled by C# exception handler and it will only return the custom error message specified in that handler.
To return a custom message, you need to return with http code like 4xx or 5xx.
new HttpResponseException(Request.CreateErrorResponse(System.Net.HttpStatusCode.Conflict, "Custom Message"));
Or you can return with 2xx and you have to parse this subscribe or then method e.g.
new System.Web.Http.Results.ResponseMessageResult(
Request.CreateResponse((HttpStatusCode)227, "Custom Error Message")
);
this.http.get().toPromise().then((response: any) => {
if (response.status == 227) {
return error;
} else {
return data;
}
return apiResponse;
}).catch(error => {
//nothing here
});
If throwing a exception is not really necessary, you can return status code 400 and a message using BadRequest:
if (headerValues.Equals("abc")) {
return BadRequest("Invalid String specified");
}
Are you explicitly catching the InvalidStringException in your .NET API controller and returning the custom message? If not, the response will be a generic HTTP 500 'Internal Server Error' response. I'd suggest explicitly catching the InvalidStringException in your .NET API controller and returning a 400 response with your custom message e.g.
try {
...
}
catch (InvalidStringException iex) {
return BadRequest(iex.message); // iex.message == Invalid String specified
}
When the InvalidStringException scenario occurs, This will return a HTTP 400 response with "Invalid String specified" as the response body. You should be able to log the error on Angular side as you're currently doing...
As other people have mentioned, you need to catch the exception and convert it to an appropriate HTTP response in your own code.
The reason for that is because if otherwise your exception is handled by ASP.NET Core using exception handling configuration you have, and it may vary:
With developer exception page
Usually in development, you will have code:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
What it does is when your environment is Development, it turns on a special page for developers to see information of unhandled exceptions. It is only in this case, you get the exception stacktrace as well as the exception message in the response body.
Without developer exception page
Conversely, if the exception page is turned off (usually off for Production environment), you will see nothing in the response body.
How to fix
Given exception handling in ASP.NET Core is a cross-cutting concern, I wouldn't use try...catch around everywhere InvalidStringException needs to be converted to HttpResponse.
I would instead use either an IActionFilter or use UseExceptionHandler which is the exception handling middleware:
Here is an example of using UseExceptionHandler in Configure method in Startup.cs:
app.UseExceptionHandler(opt => opt.Run(
async ctx =>
{
var feature = ctx.Features.Get<IExceptionHandlerFeature>();
if (feature.Error is InvalidStringException ex)
{
await ctx.Response.WriteAsync(ex.Message);
}
}));
In this way, your InvalidStringException is handled globally in your application, without explicit try...catch. And you could throw the exception anywhere in your code, the above code would catch the exception and properly convert it to an HTTP response with your own message as the body.
Also note, because you are calling the API from an Angular app, so chances are you might need to set CORS up in your API application if the two applications run from different origins.
Without CORS, your HTTP request from the Angular app may fail before it can reach your API. In this case, the status of the HTTP response in your Angular app may be undefined. And in your console, you could see CORS errors.
you can use http interceptor to create general error handler for all http error in angular app,this way you can use alert ,redirect to login page in case token expired ,overwrite the error object and more but you can still access to the error object at the component level by add a callback for observable error.
Error Handler Service
#Injectable()
export class ErrorHandlerService implements HttpInterceptor {
constructor(private msgServ: MessageService) {}
public intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
return next.handle(req).pipe(
catchError((err: HttpErrorResponse) => {
switch (err.status) {
case 500: {
this.msgServ.add({
severity: "error",
summary: "Error ",
detail: "Server is gone..💀"
});
break;
}
case 400: {
this.msgServ.add({
severity: "error",
summary: "Error ",
detail: "custome error message..."
});
break;
}
case 401: {
if (err.message == "invalid_token") {
// router 👉 navigate to login
}
break;
}
default: {
this.msgServ.add({
severity: "error",
summary: "Error ",
detail: err.message
});
}
}
return throwError(err);
})
);
}
}
add the Interceptor to Providers in app module
#NgModule({
....
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: ErrorHandlerService, multi: true },
MessageService
],
....
})
export class AppModule {}
demo 🚀
MessageService is related to primeng component library ,you can use your own alert structure
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'm making Xamarin.Forms app which should get JSON from api and then allow to display it. My code so far:
public async void jsonDownload()
{
connect();
await downloadData();
}
public void connect()
{
client = new HttpClient();
client.MaxResponseContentBufferSize = 256000;
}
public async Task<List<Jsonclass>> downloadData()
{
String url = "https://my-json-server.typicode.com/kgbzoma/TestJsonFile/all";
var uri = new Uri(string.Format(url, string.Empty));
try
{
var response = await client.GetAsync(uri).ConfigureAwait(false);
response.EnsureSuccessStatusCode(); //NEVER GET HERE
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
List = JsonConvert.DeserializeObject<List<Jsonclass>>(content);
}catch (Exception ex)
{
Debug.WriteLine(#" Error {0}", ex.Message);
}
return List;
}
Problem is that code don't even go to response.EnsureSuccessStatusCode(); so my list of objects is empty. On UWP version it's working without any problems.
Here i'm gettin exception: System.Net.Http.HttpRequestException with message An error occurred while sending the request.
SecureChannelFailure (The authentication or decryption has failed.)
or
System.Net.WebException: Error: TrustFailure
or
Mono.Security.Protocol.Tls.TlsException: Invalid certificate received from server.
By default, Xamarin.Android uses the older Mono Managed HttpClient handler that does not support TLS 1.2.
Open your Xamarin.Android project settings, goto Build / Android Build / General and use the AndroidClientHandler.
This will add the following MSBuild properties directly to your .csproj
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
<AndroidTlsProvider>btls</AndroidTlsProvider>
Note: If doing this manually in the .csproj, you need to add them to the debug AND release PropertyGroup.
Or programmatically set the HttpClient to use it:
client = new HttpClient(new AndroidClientHandler());
Note: You should be looking at the InnerException for these types of errors
catch (Exception ex)
{
Console.WriteLine(#" Error {0}", ex.Message);
Console.WriteLine(#" Error {0}", ex.InnerException?.Message);
}
I have been venturing in the ServiceStack's documentation regarding an issue with throwing Exceptions from an Action that returns a Stream.
The issue is that while all the other Actions in my service return beautiful errors like:
{
"ResponseStatus": {
"ErrorCode": "ArgumentException",
"Message": "Unable to load data",
"StackTrace": "[GetData: 7/11/2016 1:02:11 PM]:\n[REQUEST: {Token:asdf,Id:1}]\nServiceStack.HttpError: Unable to load codes from token ---> System.ArgumentException: Unable to load codes from token.............(abridged)
}
}
There is an Action with the return type as Stream from which, regardless of the type of exception returned, the http client receives the following response:
With the handler (as per the SS documentation):
Error: ArgumentNullException: As result 'ErrorResponse' is not a supported responseType, a defaultAction must be supplied
Parameter name: defaultAction
And without any handlers:
'no content'
400
Any help will be greatly appreciated.
Sample Code-->
Here is an example of the Action:
[AddHeader(ContentType = "application/pdf")]
public Stream Get(GetPdfRequest request)
{
throw new NotImplementedException("FAKE EXCEPTION");
}
and in the APPHOST's Configure() method:
this.UncaughtExceptionHandlers.Add((req, res, operationName, ex) =>
{
var logger = LogManager.GetLogger(GetType());
logger.Error("Unhandled error in API during request binding.", ex);
res.Write("Error: {0}: {1}".Fmt(ex.GetType().Name, ex.Message));
res.EndRequest(skipHeaders: true);
});
this.ServiceExceptionHandlers.Add((httpReq, request, exception) =>
{
var logger = LogManager.GetLogger(GetType());
logger.Error("Unhandled error in API.", exception);
//call default SS exception handler
return DtoUtils.CreateErrorResponse(request, exception);
});
Here is a screenshot of what I see on the Swagger Rest client when the above Action is called.
The issue is due to being unable to serialize the ErrorResponse DTO into the unregistered "application/pdf" ContentType.
I've just added a fallback to use the Config.DefaultContentType for serializing errors in unregistered Content Types in this commit, available from v4.0.61 that's now available on MyGet.
A workaround for prior versions of ServiceStack is instead of using the [AddHeader] Request Filter Attribute, to instead set the Content-Type in the Service implementation just before you serialize, so any Exceptions are thrown before Response ContentType is set, e.g:
public class ErrorStream {}
public class ErrorStreamService : Service
{
public Stream Any(ErrorStream request)
{
if (!IsValid(request))
throw new NotImplementedException("Exception in Stream Response");
base.Request.ResponseContentType = "application/pdf";
return PdfAsStream(request);
}
}
Which throws a Typed Exception when using a Service Client:
try
{
var response = client.Get<Stream>(new ErrorStream());
Assert.Fail();
}
catch (WebServiceException ex)
{
Assert.That(ex.IsAny400());
Assert.That(!ex.IsAny500());
Assert.That(ex.ErrorCode, Is.EqualTo("NotImplementedException"));
Assert.That(ex.StatusCode, Is.EqualTo((int)HttpStatusCode.MethodNotAllowed));
}
Also UncaughtExceptionHandlers is only for handling Exceptions thrown outside of a Service, exceptions that occur within a Service are instead handled by ServiceExceptionHandlers instead, but be careful when modifying the default Exception handling behavior as you can invalidate the typed Exception handling on the client.