I want to implement custom exception handling in web API.
I am able to implement some initial implementation, However I want to pass class object to exception to display all attributes. like
class error
{
int error_code
string error_message
string API
}
When some error occur it should show json like
{
"error_code": 0,
"error_message":"Either Your are not authorized or you don't have any project yet.",
"API": "save data"
}
This code only show the message
throw new HttpResponseException(
Request.CreateErrorResponse(HttpStatusCode.NotFound, message));
Any suggestion,
Thanks
You just need to give your object as input for the CreateResponse method. Generate the error response as follows,
return Request.CreateResponse(HttpStatusCode.BadRequest, error,
new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
The web API will automatically json-fies the error object you passed.
Make sure you set the necessary values in the error object before you do this.
Hope this helps.
EDIT
Set your HttpStatusCode as BadRequest instead of NotFound since you are generating the exception. It's more appropriate.
Related
I am new to Asp.net core web API.
is return Problem(errorMessage) is the right way to return any kind of error in asp.net core if we are not sure about a particular status code.
below is my code,
[HttpPost]
public async Task<ActionResult> Post([FromForm] MyModel request)
{
var (success,statuscode, errorMessage) = await _service.MyMethod(Id, request);
return success ? Ok() : Problem(errorMessage, statusCode: statuscode);
}
MyMethod method will either return BadRequest or UnprocessableEntity status code if any error will come.
So,is it a right way to return the error in Problem()?
Thanks in advance!
For any validation issues, you should return UnprocessableEntity which is 422 if you want to go by the book and add the details on ProblemDetails(check below).
Now, this is not mandatory. At the end of the days your api is a contract between you and your client, and you should define this hand check for your integration. What are you expecting on the server side and what is the client going to receive.
Now for global exceptions you can inject a middleware and capture them and provide a specified details of what happened. In this case you should return a ProblemDetails instance.
ProblemDetails class
The ietf tried to create a standard by specifying the details of this class.
Now by default when you return this type you should include as well a MediaType, if the request was a get, you should return as part of the headers Accept: application/problem + json
Using a post you will be adding Content-Type:application/problem + json instead.
My recommendation:
Now for Validation issues you can check for ModelState.IsValid and if there is any error of your model it should be on the Errors property.
For exceptions go with the middleware.
Now this is not a blue print. You can extend the class or the customer may use another type of format to process your responses in case of any errors, at the end of the day as I said, this is a contract between you and your client.
I have an ASP.NET Core application and I'm attempting to handle HTTP responses with status codes between 400 and 599 by using UseStatusCodePagesWithRedirects.
In Startup.cs I've added the following:
app.UseStatusCodePagesWithRedirects("/Error");
My Error controller is empty except for the following action (which was taken from the default scaffolded Home controller):
[Route("Error")]
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
This works perfectly when I call return new BadRequestResult(); or return NotFound(); from one of my controllers, but when I try to return an error with more detail (such as including an error object) the controller action is never called and the body of the response is displayed on screen as plaintext instead. As an example, the following statement does not trigger the Error controller:
context.Result = new BadRequestObjectResult({ Errors = errors });
If I use the following statement instead, the middleware is correctly called:
context.Result = new BadRequestResult();
This appears to be working as designed, as the documentation states that UseStatusCodePagesWithRedirects "checks for responses with status codes between 400 and 599 that do not have a body" (emphasis mine) and the source code backs this up.
I want to include more information on my error page (such as user friendly error messages where appropriate) but I can't figure out how I can pass the data across effectively using the middleware since I'm trying to avoid my controllers knowing too much about how errors are handled so that the logic can be contained in one place and potentially changed later.
Is there a way to return a HTTP error that has additional information but will still get picked up by UseStatusCodePagesWithRedirects?
This is not how the exception handling middleware works. I'm not sure what you're doing exactly, but it looks like you're attempting to return BadRequest from middleware or an action filter. If you want to intercept some error there, you should simply allow the exception to bubble up (or throw one), not return a response, as that way, you'll keep the context of what happened.
Inside your error action, you can use HTTP feature interfaces to get the data you're looking for then. For example, there's:
var exceptionHandlerPathFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();
If there was an exception, you can access it then via exceptionHandlerPathFeature.Error. There's also IStatusCodeReExecuteFeature, which you can use to get the original URL of the request for things like 404s:
var statusCodeReExecuteFeature = HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
if (statusCodeReExecuteFeature != null)
{
OriginalURL =
statusCodeReExecuteFeature.OriginalPathBase
+ statusCodeReExecuteFeature.OriginalPath
+ statusCodeReExecuteFeature.OriginalQueryString;
}
Source
Depending on exactly what you're doing, there might be other ways as well.
The below is not exactly what you need (passing an error details/an error object) but it seems like you can pass an error code, at least in ASP.NET Core.
If you look at the documentation for UseStatusCodePagesWithRedirects, it says that you can pass a status code, since the url template may contain such parameter:
app.UseStatusCodePagesWithRedirects("/MyStatusCode?code={0}");
Then in your MyStatusCode.cshtml you can intercept it like:
#{
var codeStr = Context.Request.Query.ContainsKey("code") ? Context.Request.Query["code"].ToString() : "-1";
}
I have created a custom object that i use to generate a json error response for all error. The issue i am having is there are some errors that i cant catch. For example, if i try to call an action that does not support GET the default response is
{"Message":"The requested resource does not support http method
'GET'."}
This is fine, but i want to control the format. I want to control every single automated error like this so i can make sure that nothing gets output that i dont want to be output. I need to be able to gracefully let the client know if a code exception occurs.
I found this and this seems to be what i am looking for, but it doesnt seem to be catching the errors as there are no matching actions for these . How to override all standard error pages in WebAPI
I tried to implement this, but i still get the same error message from above even when i have this in the main controller.
[AllowAnonymous]
[ActionName("405")]
[HttpGet]
public string Status405()
{
return "error";
}
I was hoping there would be an onerror event or something that would act as a catch all so i could override everything. I tried to work based off the HttpResponseEx
public class ErrorFilter : System.Web.Http.HttpResponseException
{
public override string Message
{
get
{
return "My custom response based on whatever params are in this error";
}
}
}
This doesnt work either and i can see why as it doesnt tap into any events that get triggered.
Surely there is a way to do this. How is it normally done?
In the web.config, you need to turn on custom errors. By default it's set to remote, which allows the developer to see the stack trace and the end user to see a nice error page. You want to set this to on. See here for more details https://msdn.microsoft.com/en-us/library/h0hfz6fc(v=vs.85).aspx
I have an asp.net web api project. In my controllers I have set up the
ExceptionFilterAttribute
To catch any errors at a global level. There are two get requests being fired off from the controller method. They are failing and so I am seeing the exception being raised in the exception filter. However the exception is not showing me details of the failed request. Is it possible to get them? For example 4 GET requests might have been invoked and one of them is failing and the exception is being thrown. But all im seeing is a message saying...
The remote name could not be resolved: 'xx.xx.com'
But I need more details, like the query string etc...
The response object on the web exception is null too :-(
Within the OnException method of your ExceptionFilterAttribute you have a parameter argument of type HttpActionExecutedContext. Within the instance of this class you can access the Request and Response properties to get all the information you need, either of the request or the response. Within the ActionContext property you can even get all routing, controller and action informations.
var requestHttpMethod = actionExecutedContext.Request.Method;
var requestUri = actionExecutedContext.Request.RequestUri;
var controllerDescriptor = actionExecutedContext.ActionContext.ControllerContext.ControllerDescriptor;
var actionDescriptor = actionExecutedContext.ActionContext.ActionDescriptor;
You can also modify the response object to return a more appropriated error message. Just look around a bit what information these classes can provide you.
I use DataAnnotations in my GUI layer to show error messages in forms, but I have some questions about how to handle exceptions from my service layer and what to show the user if they occur.
To communicate with my service layer I use a request and response class. For example:
public class RegisterUserRequest
{
public string Username { get; set; }
public string Password { get; set; }
public string Email { get; set; }
}
Should I check for nulls in my request class inside the setter methods? Or should I do this in my service? I think it makes sense to do this on both the request and response setter methods and throw an ArgumentNullException if a parameter is null.
In my service class I throw an InvalidOperationException when for example the username or password is invalid. Is this the right exception to throw?
Another question I have is if I should catch all exceptions, and if so, what do I tell the user about the exception? If for example some property is null, it should throw an ArgumentNullException. But should I let the user know about this?
When an username is invalid I throw an InvalidOperationException. This one I do want to show to the user because it tells the user that it should use at least 3 characters or something.
I think I should use the error message from the InvalidOperationException to show to users and redirect to a standard error view when other exceptions occur like: "Oops, something went wrong".
I think a more relevant exception to throw when the username or password is invalid is an ArgumentException. In the description of that exception type it specifically covers the case where an argument is invalid.
As for passing the exception to the user, you should try to inform the user of the error without exposing any of the inner workings of your service, so having a response message containing the error "Invalid username - must be at least 3 characters" will give them useful feedback.
For errors that you don't want to pass on in detail I would suggest logging an error message yourself and then passing the error ID to the user. e.g. "An unhandled error has occured. Please contact support, quoting error ID xxx". This should only be used as a last resort however - it is better to inform the user how to fix it but this would be a suitable way to catch all errors without passing too much information to the client.
I would simply use DataAnnotations again because no-one wants to be redirected an error page if they don't put the correct formatting in for their username or password.