Kras
Kras

Reputation: 623

MVC Custom Action Attribute

During testing (at least) we're logging some low-level information for each controller/action. All controllers are derived from our custom BaseController which overrides OnActionExecuting to do the logging.

We have a property in the BaseController that determines whether or not this logging will occur, so that a controller can override OnActionExecuting itself, reset the flag, and then call "base.OnActionExecuting". The flag is normally true, but we'd want to turn it off for some Json requests, for example.

What we'd prefer to do is create a custom controller/action filter to handle that, something like this:

[LogPageAccess(false)]
[HttpGet]
Public ActionResult Foobar()

I'm sure there's a way to do it, but I haven't been able to figure out how to create the custom attribute and have it reset the flag in the BaseController.

Thanks...

Upvotes: 3

Views: 5437

Answers (2)

davecoulter
davecoulter

Reputation: 1826

I tried to build out a simple example of your situation for a while, but then realized that I couldn't pass instance data to an Attribute-- so say if I set a Log flag to false, I couldn't use that to directly manipulate the base controller's property.

Check out this SO post.

Here was the code I was playing around with (does not compile -- can't pass this):

public class BaseController : Controller
{
    public bool LogPageRequests { get; set; }
}

public class LogPageAccess : ActionFilterAttribute
{
    public LogPageAccess(BaseController baseController, bool log = true)
    {
        baseController.LogPageRequests = log;
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        //Do Whatever
        base.OnActionExecuting(filterContext);
    }
}

public class SomeController : BaseController
{
    [LogPageAccess(this, false)]
    public ActionResult Index()
    {
        return View();
    }
}

Maybe you can do something with reflection, but it might be the case that you'll have to do it the way you've been doing it since it just doesn't seem possible to get instance data to the attribute.

Upvotes: 0

João Louros
João Louros

Reputation: 2760

in my project I use the following to verify access controllers:

    [Capability(UserCapability.FileManagement)]
    public ActionResult FileList(FileListRequestModel request, bool ajax = false)
    {
        //code
    }

Here is my Capability Class

/// <summary>
/// Decorator to MVC class and method to evaluate if a certain capability is enabled
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CapabilityAttribute : AuthorizeAttribute
{
    #region Class Attributes

    private object _capability = null;

    #endregion

    #region Public Methods

    /// <summary>
    /// Create a new capability attribute
    /// </summary>
    /// <param name="capability">Context Value passed to the validator</param>
    public CapabilityAttribute(object capability)
    {
        this._capability = capability;
    }

    /// <summary>
    /// Check if attribute is enabled
    /// </summary>
    /// <param name="filterContext"></param>
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        if (!Capability.Enabled(this._capability))
        {
            throw new UnauthorizedAccessException();
        }
        else
        {
            base.OnAuthorization(filterContext);
        }
    }

    #endregion
}

You just need to adapt this code for your case, I hope it become useful

Upvotes: 2

Related Questions