Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Actionfilter Injection in ASP.NET MVC 5

I have a simple filter.

public class IsAdmin : ActionFilterAttribute, IAuthenticationFilter
{
    private string _roleName;
    IBusinessIdentity _identity;

    public IsAdmin(string roleName, IBusinessIdentity identity)
    {
        this._roleName = roleName;
        this._identity = identity;
    }

    public void OnAuthentication(AuthenticationContext filterContext)
    {
    }

    public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
    {
        if (!_identity.Roles.Contains(_roleName))
            filterContext.Result = new HttpUnauthorizedResult();
    }
}

I am using Ninject. Here is my controller. I'm trying to get the injected service into my ActionFilter in order not to take a dependency on HttpContext but instead on my IBusinessIdentity.

IBusinessIdentity gets injected the HttpContext.User.Identity`. And it does a few database calls and gets the userRoles.

public class HomeController : Controller
{
    readonly IBusinessIdentity _identity;

    public HomeController(IBusinessIdentity identity)
    {
        this._identity= identity;
    }

    [IsAdmin("Admin", _identity)]
    public ActionResult Index()
    {
        return View();  
    }
}

This does not work and I'm getting a compiler error when I try to put the "identity" in the actionfilter constructor at compile time.

An object reference is required for the non-static field, method, or property

I need this because I'm planning to test various permissions with the identity.

I am thinking some kind of reflection to be done after controllers gets instantiated. I have a very vague idea on how it could be done.

I am using ASP.NET MVC 5 and I don't have the kernel.bindfilter. I can't use older version.

I am well aware of this hack.

Action filter constructor being called repeatedly for single controller

https://github.com/ninject/Ninject.Web.Mvc/wiki/Conditional-bindings-for-filters

How can I accomplish the same maybe effect using Ninject for MVC 5.

EDIT: massive failure

I forgot to include the:

using Ninject.Web.Mvc.FilterBindingSyntax;

Now everything works as explained in the above links.

Now I need to figure out how to inject the "roleName" string in the filter constructor. Although I think just construct a filter for every role. I will post entire code later.

like image 427
Aflred Avatar asked Dec 25 '22 22:12

Aflred


1 Answers

Although your question is different, the answer is exactly the same as this one.

DI friendly attributes should never define any behavior. You need to separate the behavior out into a separate filter that can have its dependencies injected at application startup. This can be done by splitting your action filter attribute into 2 parts.

  1. An attribute that contains no behavior to flag your controllers and action methods with.
  2. A DI-friendly class that implements IActionFilter and/or IAuthenticationFilter that contains the desired behavior with a scanning implementation to check for the attribute.

Don't let Microsoft's marketing of ActionFilterAttribute fool you. That approach is completely hostile to DI.

like image 194
NightOwl888 Avatar answered Jan 01 '23 12:01

NightOwl888