Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access Controller from ExceptionFilterAttribute in ASP.NET Core

With ASP.Net Core 2, how could you get access to the Controller instance that an ExceptionFilterAttribute is applied to?

Is there a better way to acheive shared "base" controller properties and methods, etc. now in Core? Such as putting it in a higher level like Startup?

Before Core, In MVC 4, I would do something like this:

/// <summary>
/// Base controller, shared by all WebAPI controllers for tracking and shared properties.
/// </summary>
[ApiTracking]
[ApiException]
public class BaseApiController : ApiController
{
    private Common.Models.Tracking _Tracking = null;
    public Common.Models.Tracking Tracking
    {
        get
        {
           if(_Tracking == null)
               _Tracking = new Common.Models.Tracking();
           return _Tracking;
        }
    }
    //... other shared properties...
}

/// <summary>
/// Error handler for webapi calls. Adds tracking to base controller.
/// </summary>
public class ApiExceptionAttribute : ExceptionFilterAttribute
{
    public override void OnException(HttpActionExecutedContext cntxt)
    {
        BaseApiController ctrl = cntxt.ActionContext.ControllerContext.Controller as BaseApiController;
        if (ctrl != null)
            ctrl.Tracking.Exception(cntxt.Exception, true);

        base.OnException(actionExecutedContext);
    }
}

/// <summary>
/// Intercepts all requests to inject tracking detail and call tracking.save.
/// </summary>
public class ApiTrackingAttribute : System.Web.Http.Filters.ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext cntxt)
    {
        //...add info to tracking
    }
    public override void OnActionExecuted(HttpActionExecutedContext cntxt)
    {
        BaseApiController ctrl = cntxt.ActionContext.ControllerContext.Controller as BaseApiController;
        if (ctrl != null)
            ctrl.Tracking.Save();
    }
}
like image 734
Zack C Avatar asked Dec 20 '17 03:12

Zack C


1 Answers

HttpContext in ASP.Net Core contains Items property of IDictionary<object, object> type for sharing the data within the scope of the request. It's exactly what you need for covering your case. Here is a sample implementation:

public class ApiExceptionAttribute : ExceptionFilterAttribute
{
    public override void OnException(ExceptionContext context)
    {
        var items = context.HttpContext.Items;
        if (items.ContainsKey("Tracking"))
        {
            Tracking tracking = (Tracking)items["Tracking"];
            tracking.Exception(context.Exception, true);
        }

        base.OnException(context);
    }
}

public class ApiTrackingAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        var tracking = new Tracking();
        //...add info to tracking

        context.HttpContext.Items.Add("Tracking", tracking);
    }

    public override void OnActionExecuted(ActionExecutedContext context)
    {
        var items = context.HttpContext.Items;
        if (items.ContainsKey("Tracking"))
        {
            Tracking tracking = (Tracking) items["Tracking"];
            tracking.Save();
        }
    }
}
like image 84
CodeFuller Avatar answered Nov 05 '22 18:11

CodeFuller