Throw exception ActionFilterAttribute OnActionExecuting - c#

I want to throw a exception in the ActionFilterAttribute like this:
public override void OnActionExecuting(ActionExecutingContext filterContext) {
base.OnActionExecuting(filterContext);
if (!_controller.HasRoleIndex()) {
throw new Exception(Resources.BackOffice.lblErrorPermission);
}
}
I want it like this, because I want to execute this code in some ajax request, and when the user dosen't have permissions, send a exception and then showing a message.
I have the code of showing the message in the exception implemented, and it works for exeptions in other places of the aplication, but when an exception is thrown in the OnActionExecuting of the ActionFilterAttribute, a unhandled exception in the application, and what I get in the view is a Server Error.
How can I handle the exception, without redirecting to another page? I only want to throw the exception, no show a 404 error page.
Edit:
To put things in context: I have a web page with some ajax calls, I wanted the ajax calls to have a behavior in case that an error ocurred while the call was made so I have something like this in all my ajaxs:
$.ajax({
...
error: function (e, o, errorText) { AlertMessages.SetErrorMessageAndShow(errorText); },
...
});
This code shows a modal window with a friendly user message with the cause of the error:
Session expired. Bad email adress, etc.
I want to use the same code for validation. And with validation I was thinking of use ActionFilterAttribute.
But I can't get how to send and exception from the OnActionExecuting.
Is this possible? or i have to return a specific Json and then in the javascript act acording the json returned?

Related

Can we do graceful error handling with ErrorBoundary?

I am trying to understand how are we suppose to use ErrorBoundary as central error handling point. There are different kinds of exceptions that could be handled by ErrorBoundary, and not to show same generic message that something went wrong.
if we wrap #Body with CustomErrorBoundary, we will caught any exception that we did not handle in our code. This is also true for 401 - Not authorized. We do not want to check for 401 on each API call, that would be a lot of repeating code. So:
protected override Task OnErrorAsync(Exception exception)
{
if (exception is HttpRequestException requestException)
{
if (requestException.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
// what to do to swallow exception and navigate to some route?
// NavigationManager.NavigateTo("/notauthorized");
}
}
}
Whatever I write in OnErrorAsync, Blazor will show CustomErrorBoundary's ErrorContent. In ErrorContent we usually put some message like: Oops, something went wrong, etc... And that is what I want to avoid, since in this case I know what went wrong, and navigate to /notauthorized, which is handled by my custom NotAuthorized component
This is a specific problem that happens when user is logged in, but does not have rights to use some resource. In this case template of AuthorizeRouteView is not handling 401, like it does when user is not logged in.
Any thoughts?

Ensure that a specific exception always results in a given HTTP response status code

Requirement
I have an ASP.Net MVC application that works with a number of different libraries. As with most libraries, various function calls may cause one of many different exceptions to be thrown.
Currently, whenever any exception is thrown, then MVC application 'handles' them and returns an "internal server error" (code 500) back to the client (eg. web browser).
This is fine for most cases, however, there is one specific exception type (in this case UnauthorizedAccessException) that I would like to result in an "Unauthorized" (code 401) status being sent in the response, instead of the usual 500 error.
Current Attempt
I did a fair bit of research and it looks like the bets way to 'catch' all exceptions and process them is by using the Application_Error method. So I tried the following implementation of Application_Error in the MvcApplication class:
protected void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
if(ex is UnauthorizedAccessException)
{
Response.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized;
}
}
Problem
The problem here is that although I can debug and see that Response.StatusCode is being set to 401, the client/browser is still receiving a 500 error.
I expect that there is a very good reason why this is happening, but I have exhausted my brain thinking of search terms that will get me the answer I need.
Question
In short, what do I need to do in order to get the behaviour I am looking for?
For additional information, ultimately what I want is for an UnauthorizedAccessException to have the same behaviour as how MVC handles unauthenticated requests (which redirects to login page). However, I also need it to work for AJAX requests in that my javascript can check for 401 error and do some specific logic (in which case a response redirect to login page is not workable)
A clever way to go about doing that is to create a Base Controller that your controllers inherit over the default Controller. There you inherit the default Controller class and override the OnException method.
public abstract class BaseController : Controller
{
protected override void OnException(System.Web.Mvc.ExceptionContext filterContext)
{
var responseCode = Response.StatusCode;
var exception = filterContext.Exception;
switch (exception.GetType().ToString())
{
case "UnauthorizedAccessException":
responseCode = 401;
filterContext.ExceptionHandled = true;
break;
}
Response.StatusCode = responseCode;
base.OnException(filterContext);
}
}
The trick that makes it work is filterContext.ExceptionHandled = true; if you don't set this to true, the server will return 500.
Your controllers will inherit the BaseController;
public class UserController : BaseController
{
public ActionResult Index(){
return View();
}
}
What you'll need to add to this code is your redirect to the login page, to your OnException method (if needed). I would do it for you but I don't have enough time to write and test it for you.. currently waiting for automated tests to finish.. :-)
Edit:
I did not realize your view could throw errors too, that obviously won't be handled by the controller.
In this case we can revert to the original Application_Error method on Global.asax.
What we need is two lines of code..
Response.StatusCode = 401;
Response.End();
First line sets the status code to 401,
Second line ends the execution at this point and triggers EndRequest event, so the StatusCode won't be modified to 500.
If you want to attach a message with your response:
Response.Write("Oops, you're not authorized...");
It would be a good idea to call Response.Clear(); before starting to modify the response object inside your Error Handler.

Model validation in Web API - Exception is thrown with out a throw statement?

I have seen the model validation from here (Under section: Handling Validation Errors).
The code-snippet is as below in Web API
public class ValidateModel : ActionFilterAttribute
{
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (actionContext.ModelState.IsValid == false)
{
actionContext.Response = actionContext.Request.CreateErrorResponse(
HttpStatusCode.BadRequest, actionContext.ModelState);
}
base.OnActionExecuting(actionContext);
}
}
The problem is upon validation of model, if there were any errors, it assigns an model state invalid exception.
And after that, before going to the actual method (which is decorated with this [ValidateModel] attribute), WebAPI simply returns a 400 request.
But how ? Which function is returning a HTTP 400?
What happens after this method is done executing? Where does the control flow ?
EDIT:
The action that I am applying this attribute to is a normal one.
[ValidateModel]
public IHttpActionResult Post([FromBody]Request)
{
//do normal business logics here.
return Ok(SuccessMessage);
}
To understand the control flow you first need to visit this link here -
Action Attribute Class Reference
Check the method sections there. If clearly states that, OnActionExecuting is performed before that particular action, decorated with this attribute, is executed and OnActionExecuted is performed after the execution is complete. Since you are implementing OnActionExecuting like this -
public class ValidateModel : ActionFilterAttribute
{
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (actionContext.ModelState.IsValid == false)
{
actionContext.Response = actionContext.Request.CreateErrorResponse(
HttpStatusCode.BadRequest, actionContext.ModelState);
}
base.OnActionExecuting(actionContext);
}
}
and since the error is thrown inside this method, like this -
if (actionContext.ModelState.IsValid == false)
{
actionContext.Response = actionContext.Request.CreateErrorResponse(
HttpStatusCode.BadRequest, actionContext.ModelState);
}
Your method will only execute if the OnActionExecuting method finds a valid model. And from the error 400, it seems that your current model state is not valid and thus it fails to succeed and your method will never be executed unless you provide a valid model. Set a debug point inside this method and you can find out why it fails.
By the way, the exception is not thrown its just a standard response that is handled by -
base.OnActionExecuting(actionContext);
http://msdn.microsoft.com/en-us/library/system.web.mvc.actionfilterattribute(v=vs.118).aspx
To find the error point just create a break point on Application_Error in Global.asax and follow the error details and stack trace to find the origin for the same.
When method OnActionExecuting is called it checks to see if the Model is valid. If Model is not valid
actionContext.Response will be calling server which will return 400 code back meaning the it was bad request.
It all depends how you are calling this web api. Normally you can have jquery or some other libraries or code behind from asp.net making the call to the webapi's with appropriate object. That object is first checked if it is valid or not. If it is valid it will keep processing nothing is returned back. If object state is invalid than it will return the status code 400. If it is returning 200 than it means your object is valid and web api executed and is returning 200. This 200 is not being returned from webapi but from EF after data was written sucessfully.
If you want to use try catch block than you dont need to check if model is valid. Just pass through the url with object and wait for response than catch it and display.
If your Request data type is defined as struct, or an abstract class, it cannot be instantiated, and that might be the probable cause. If is a struct, just make it Nullable, if it is an abstract class or interface you can either create your own ModelBinder to deal with the creation, or you can change it with a concrete implementation.
In VBA.NET API REST
Validate model
Imports System.ComponentModel.DataAnnotations
Public Class Client
<Required(ErrorMessage:="Dpi is required")>
Public Property Dpi As String
<MaxLength(16, ErrorMessage:="El NAME no debe ser mayor a 16 caracteres.")>
Public Property NAME As String
End Class
CONTROLLER
<Route("UPDATE/client")>
<ActionName("description to do...")>
<HttpPost>
Public Function saveClient(ByVal cli As Client)
If ModelState.IsValid Then
return Request.CreateResponse(HttpStatusCode.OK, True)
Else
Return BadRequest(ModelState)
End If
End Function

Exception handling in Controller (ASP.NET MVC)

When an exception is thrown by your own code that's called from an action in a controller how should that be handled? I see a lot of examples of best practices where there are no try-catch statements at all. For example, accessing data from a repository:
public ViewResult Index()
{
IList<CustomModel> customModels = _customModelRepository.GetAll();
return View(customModels);
}
Clearly this code could throw an exception if the call is to a database that it can't access and we are using an ORM like Entity Framework for example.
However all that I can see will happen is that the exception will bubble up and show a nasty error message to the user.
I'm aware of the HandleError attribute but I understand it's mostly used to redirect you to an error page if an exception that's unhandled occurs.
Of course, this code could be wrapped in a try-catch but doesn't separate nicely, especially if you have more logic:
public ViewResult Index()
{
if (ValidationCheck())
{
IList<CustomModel> customModels = new List<CustomModel>();
try
{
customModels = _customModelRepository.GetAll();
}
catch (SqlException ex)
{
// Handle exception
}
if (CustomModelsAreValid(customModels))
// Do something
else
// Do something else
}
return View();
}
Previously I have extracted out all code that could throw exceptions like database calls into a DataProvider class which handles errors and returns messages back for showing messages to the user.
I was wondering what the best way of handling this is? I don't always want to return to an error page because some exceptions shouldn't do that. Instead, an error message to the user should be displayed with a normal view. Was my previous method correct or is there a better solution?
I do three things to display more user-friendly messages:
Take advantage of the global exception handler. In the case of MVC: Application_Error in Global.asax. Learn how to use it here: http://msdn.microsoft.com/en-us/library/24395wz3(v=vs.100).aspx
I subclass Exception into a UserFriendlyException. I do my very best in all of my underlying service classes to throw this UserFriendlyException instead of a plain old Exception. I always try to put user-meaningful messages in these custom exceptions. The main purpose of which is to be able to do a type check on the exception in the Application_Error method. For the UserFriendlyExceptions, I just use the user-friendly message that I've set deep down in my services, like "Hey! 91 degrees is not a valid latitude value!". If it's a regular exception, then it's some case I haven't handled, so I display a more generic error message, like "Oops, something went wrong! We'll do our best to get that fixed!".
I also create an ErrorController that is responsible for rendering user-friendly views or JSON. This is the controller whose methods will be called from the Application_Error method.
EDIT:
I thought I'd give a mention to ASP.NET Web API since it's closely related. Because the consumer of Web API endpoints won't necessarily be a browser, I like to deal with errors a little differently. I still use the "FriendlyException" (#2 above), but instead of redirecting to an ErrorController, I just let all my endpoints return some kind of base type that contains an Error property. So, if an exception bubbles all the way up to the Web API controllers, I make sure to stick that error in the Error property of API response. This error message will either be the friendly message that has bubbled up from the classes the API controller relies on, or it will be a generic message if the exception type is not a FriendlyException. That way, the consuming client can simply check whether or not the Error property of the API response is empty. Display a message if the error is present, proceed as usual if not. The nice thing is that, because of the friendly message concept, the message may be much more meaningful to the user than a generic "Error!" message. I use this strategy when writing mobile apps with Xamarin, where I can share my C# types between my web services and my iOS/Android app.
With Asp.Net MVC you can also override the OnException method for you controller.
protected override void OnException(ExceptionContext filterContext)
{
if (filterContext.ExceptionHandled)
{
return;
}
filterContext.Result = new ViewResult
{
ViewName = ...
};
filterContext.ExceptionHandled = true;
}
This allow you to redirect to a custom error page with a message that refer to the exception if you want to.
I used an OnException override because I have several projects referenes to one that have a Controller that handle errors:
Security/HandleErrorsController.cs
protected override void OnException(ExceptionContext filterContext)
{
MyLogger.Error(filterContext.Exception); //method for log in EventViewer
if (filterContext.ExceptionHandled)
return;
filterContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;
filterContext.Result = new JsonResult
{
Data = new
{
Success = false,
Error = "Please report to admin.",
ErrorText = filterContext.Exception.Message,
Stack = filterContext.Exception.StackTrace
},
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
filterContext.ExceptionHandled = true;
}
All questions like this are not very constructive, because the answer is always "it depends", because there are so many ways of dealing with error handling.
Many people like to use the HandleError method, because any exception is basically non-recoverable. I mean, what are you going to do if you can't return the objects? You're going to show them an error anyways, right?
The question becomes, how you want to show them the error. If showing them an error page is acceptable, than HandleError works fine, and provides an easy place to log the error. If you're using Ajax or want something fancier, then you need to develop a way to do that.
You talk about a DataProvider class. That's basically what your Repository is. Why not build that into your repository?

Handle Exception .NET MVC Keeping form data

I am trying to handle all exceptions at my c# MVC application.
All controllers inherit from BaseController, so I thought I could override the OnException (protected override void OnException(ExceptionContext filterContext)).
But I donĀ“t want to redirect to an error page, what I would like to do is to go back to the page that originated the request keeping its state. So if I had a form with an input filled by user, after handling the exception I want to show back that form with its input with the information filled by user.
Note: not all views are strongly typed.
example:
USER: myuser <-- text entered in input tag
After handling exception I want to go back to previous view showing exception message.
USER: myuser <-- text entered in input tag
My exception message
Validation should not be treated as unhandled exceptions! Please read about Model Validation in ASP.NET MVC in order to handle this scenario.
Unhandled exception is, as its name suggests, something that occurs only in exceptional cases. An exceptional case is something that when it occurs your application cannot process the request. So it doesn't make sense to redirect to a known state because there's no state when an unhandled exception occurs. The best you could do in this case is log the exception for further analysis and redirect the user to a 500 error page informing him that something went wrong.
Conclusion:
Use Model Validation to handle validation logic
Use OnException for unhandled exceptions.

Categories

Resources