简体   繁体   中英

ActionFilterAttribute on Controller vs action method

I have a LoggingAttribute which logs request and response in OnActionExecuted method:

public class LoggingAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(HttpActionExecutedContext httpContext)
    {
            //Logger.Log();
    }
}

There is another attribute for validating the request and return BadRequest . This return response from OnActionExecuting method:

public class ValidateModelAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        var modelState = actionContext.ModelState;
        if (!modelState.IsValid)
        {
            actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, modelState);
        }
    }
}

Now, when I apply both these attributes on Action method, my BadRequest s are not being logged but when I apply LoggingAttribute on controller level and ValidateModelAttribute on action method, BadRequest s are getting logged ( OnActionExecuted of LoggingAttribute getting called).

Can someone please explain this behaviour ie OnActionExecuted getting called even when action method is not being executed when attribute applied at controller.

You need to apply LoggingAttribute first on action method,

       [LoggingAttribute]
        [ValidateModelAttribute]        
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }

I tried you scenario like as below at my end

[HttpGet]
[ValidateModelAttribute]
[LoggingAttribute]
public void test()
{
   //throw new NotImplementedException("This method is not implemented");
}

With the same code as yours and I found same issue as you , your LogginAttribute not get called because you are setting repose for context in your ValidateModelAttribute , as request get response it returns immediately(because of this actionContext.Response = ) as request got response , and then it even doesnt call you method on which you applied attribute.

So solution for this part is you have to write OnActionExecuting which get called before your Validationattribute OnActionExecuting method, and your code will log as OnActionExecuting method of LoggingAttribute before you are returning response.

public class LoggingAttribute : ActionFilterAttribute
{
   public override void OnActionExecuting
      (System.Web.Http.Controllers.HttpActionContext actionContext)
        {
            //Logger.Log();
        }

   public override void OnActionExecuted(HttpActionExecutedContext httpContext)
        {
            //Logger.Log();
        }
}

and also change order or attribute , reason for doing below is when Response is set then in that case it get return from that point only , so whatever filter is there in pipe line after than is not get called.

[HttpGet]
[LoggingAttribute]
[ValidateModelAttribute]
public void test()
{
   //throw new NotImplementedException("This method is not implemented");
}

as suggested in below answer by @programtreasures

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM