aspnet / AspNetWebStack

ASP.NET MVC 5.x, Web API 2.x, and Web Pages 3.x (not ASP.NET Core)
Other
858 stars 354 forks source link

How can I catch the exception happened in OnActionExecuting method of ActionFilterAttribute? #235

Closed chucklu closed 5 years ago

chucklu commented 5 years ago
  1. I am using the ActionFilterAttribute to implement my model validation as introduced in Model Validation in ASP.NET Web API. I did security hash check for my parameters, and exception happened here

    public class ValidateModelAttribute : ActionFilterAttribute
    {
    public override async void OnActionExecuting(HttpActionContext actionContext)
    {
           if (!actionContext.ModelState.IsValid)
            {
                actionContext.Response = actionContext.Request.CreateErrorResponse(
                    HttpStatusCode.BadRequest, actionContext.ModelState);
            }
            else
            {
                var request = actionContext.Request;
                HttpResponseMessage responseMessage = new HttpResponseMessage();
                //security hash check logic here  (Exception happens here)
                //and the StatusCode will be set after checking
                if (!responseMessage.IsSuccessStatusCode)
                {
                    actionContext.Response = responseMessage;
                }
            }
    }
    }

    However, the global exception handler did not catch this exception and write a text log as expected. Inherit from ExceptionHandler to write txt log.

  2. When I check the source code of ActionFilterAttribute, I find code like this:

    public virtual Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
        {
            try
            {
                OnActionExecuting(actionContext);
            }
            catch (Exception ex)
            {
                return TaskHelpers.FromError(ex);
            }
    
            return TaskHelpers.Completed();
        }
  3. I guess you might hide the exception by catch block, so I inherit the ActionFilterAttribute and override the OnActionExecutingAsync method.

    //I have copy the source code of TaskHelpers to my local project
    public class CustomActionFilterAttribute : ActionFilterAttribute
    {
        public override Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
        {
            try
            {
                OnActionExecuting(actionContext);
            }
            catch (Exception ex)
            {
                //CreateLog(LogLevel.Error, ex);   //write exception log to txt
                return TaskHelpers.FromError(ex);
            }
    
            return TaskHelpers.Completed();
        }
    }

    Then I make ValidateModelAttribute inherit from the new created CustomActionFilterAttribute, then I try to debug the exception.

Before execute the OnActionExecuting in ValidateModelAttribute, it first execute OnActionExecutingAsync in CustomActionFilterAttribute. And the exception throwed from OnActionExecuting of ValidateModelAttribute, and it supposed to be caught in OnActionExecutingAsync of CustomActionFilterAttribute.

However, when I hit F11 to debug, the exception just disappeared and finish the OnActionExecuting(actionContext). How could it be possible? Who knows something about this weird thing?

chucklu commented 5 years ago

The version of web api I am using is 5.2.7

<package id="Microsoft.AspNet.WebApi.Client" version="5.2.7" targetFramework="net472" />
  <package id="Microsoft.AspNet.WebApi.Core" version="5.2.7" targetFramework="net472" />
  <package id="Microsoft.AspNet.WebApi.Owin" version="5.2.7" targetFramework="net472" />
chucklu commented 5 years ago

Find the problem caused by the wrong usage of async keyword in public override async void OnActionExecuting(HttpActionContext actionContext). Previously, I have an await statement in my method string requestBody = await request.Content.ReadAsStringAsync();, I removed it and forgot to remove the async keyword from method.

two alternative solutions: 1.remove the async keyword and no need to inherit CustomActionFilterAttribute 2.do not remove async keyword and await the OnActionExecuting method in CustomActionFilterAttribute's OnActionExecutingAsync method.