Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redirect user when error occurs in async controller action

I have an ASP.NET MVC 4 web application that retrieves data from a data source via WCF services.

I have set up most of controllers to be Async and subsequent methods to be Task based.

I have encountered a problem though. If an exception occurs in my code, the page being loaded just continues to load and in the end times-out with the IIS error page showing.

I have a friendly error message set up and works fine for sync actions but not async ones. The action just keeps running even though an exception may have occurred at a different level. I tried applying the AsyncTimeout attribute to the controller action but no luck, page just keeps loading for a long period of time.

Any ideas how I could handle this in my code, preferably at a global type level and direct the user to an error page when an issue occurs with an async controller action?

like image 719
amateur Avatar asked Jun 05 '14 23:06

amateur


2 Answers

Approach #1

Set customErrors to On or RemoteOnly in Web.config

<system.web>
    <customErrors mode="On" />
</system.web>

Use HandleErrorAttribute with custom error view

[AsyncTimeout(1000)]
[HandleError(ExceptionType=typeof(System.TimeoutException), View="Timeout")]
public async Task<ActionResult> AsyncActionResultReport()
{

Approach #2

Override the OnException Method of your Async Controller, or use a custom Exception Attribute

public override void OnException(ExceptionContext filterContext)
{
    if(filterContext.Exception is TimeoutException && filterContext.Controller is AsyncController)
    {
        filterContext.HttpContext.Response.StatusCode = 200;
        filterContext.Result = new RedirectToRouteResult(
                new RouteValueDictionary {
                    { "Controller", "Home" },
                    { "Action", "TimeoutRedirect" }
        filterContext.ExceptionHandled = true;
    }

    base.OnException(filterContext);
}
like image 74
Dave Alperovich Avatar answered Oct 21 '22 16:10

Dave Alperovich


If you want to do controller level, the HandleError as suggested by Dave A is perfect. But for applying HandleError Attribute at Global Level you have to use ExceptionFilter.

You can also apply the HandleError Attribute for the entire application by registering it as a global error handler. For registering a global error handler, open the FilterConfig.cs file with in App_Start folder to find the RegisterGlobalFilters method. By default, ASP.NET MVC template has already registered a global HandleErrorAttribute to the GlobalFilterCollection for your application. Here you can also add your own custom filter to the global filter collection as well like :

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
  filters.Add(new HandleErrorAttribute
  {
    ExceptionType = typeof(System.TimeoutException),
    View = "TimeoutExceptionView"
  });

  filters.Add(new HandleErrorAttribute()); //by default added
}

For details refer:

http://www.dotnet-tricks.com/Tutorial/mvc/19D9140313-Exception-or-Error-Handling-and-Logging-in-MVC4.html

OR

Alternatively you can use Application_Error(NOT Recommended) to catch exception & redirect to required action like:

protected void Application_Error(object sender, EventArgs e)
{
    Exception exception = Server.GetLastError();
    System.Diagnostics.Debug.WriteLine(exception);
    if (exc.GetType() == typeof(TimeoutException)
    {
      Response.Redirect("/Home/ErrorView");
    }
}
like image 22
Pranav Singh Avatar answered Oct 21 '22 18:10

Pranav Singh