Actionfilter Injection in ASP.NET MVC 5

2019-05-07 06:00发布

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.

1条回答
The star\"
2楼-- · 2019-05-07 06:32

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.

查看更多
登录 后发表回答