How to use Ninject to inject services into an auth

2020-07-09 09:57发布

问题:

I am using asp.net mvc 3, ninject 2.0 and the ninject mvc 3 plugin.

I am wondering how do I get service layers into my filter(in this case an authorization filter?).

I like to do constructor inject so is this possible or do I have to property inject?

Thanks

Edit

I have this for property inject but my property is always null

  [Inject]
        public IAccountService AccountServiceHelper { get; set; }


        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            // check if context is set
            if (httpContext == null)
            {
                throw new ArgumentNullException("httpContext");
            }

            // check if user is authenticated
            if (httpContext.User.Identity.IsAuthenticated == true)
            {
                // stuff here
                return true;
            }

            return false;
        }



    /// <summary>
    /// Application_Start
    /// </summary>
    protected void Application_Start()
    {

        // Hook our DI stuff when application starts
        IKernel kernel = SetupDependencyInjection();

        RegisterMaps.Register();

        AreaRegistration.RegisterAllAreas();

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);

    }


    public IKernel SetupDependencyInjection()
    {
        IKernel kernel = CreateKernel();
        // Tell ASP.NET MVC 3 to use our Ninject DI Container
        DependencyResolver.SetResolver(new NinjectDependencyResolver(kernel));

        return kernel;
    }

    protected IKernel CreateKernel()
    {
        var modules = new INinjectModule[]
                          {
                             new NhibernateModule(),
                             new ServiceModule(),
                             new RepoModule()
                          };

        return new StandardKernel(modules);
    }


public class ServiceModule : NinjectModule
{
    public override void Load()
    {
        Bind<IAccountService>().To<AccountService>();
    }

}

Edit

I upgraded to ninject 2.2 and get finally got it work.

Edit 2

I am going to try and do the constructor way for my authorize filter but I am unsure how to pass in the Roles. I am guessing I have to do it through ninject?

Edit 3

This is what I have so far

 public class MyAuthorizeAttribute : AuthorizeAttribute 
    {
        private readonly IAccountService accountService;

        public MyAuthorizeAttribute(IAccountService accountService)
        {
            this.accountService = accountService;
        }

        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            return base.AuthorizeCore(httpContext);
        }
    }

  this.BindFilter<MyAuthorizeAttribute>(FilterScope.Controller, 0)
                .WhenControllerHas<MyAuthorizeAttribute>();

  [MyAuthorize]
    public class MyController : BaseController
    {
}

It tells me it want's a no parameter constructor. So I must be missing something.

回答1:

The problem with filters is that they are attributes. And if you define a constructor of an attribute that expects some dependency you will never gonna be able to apply it to any method: because all values that you pass to attributes must be known at compile time.

So basically you have two possibilities:

  1. Use Ninject to apply the filter globally instead of decorating your controllers/actions with it:

    public interface IFoo { }
    public class Foo : IFoo { }
    
    public class MyFooFilter : AuthorizeAttribute
    {
        public MyFooFilter(IFoo foo)
        {
    
        }
    }
    

    and then configure the kernel:

    kernel.Bind<IFoo>().To<Foo>();
    kernel.BindFilter<MyFooFilter>(FilterScope.Action, 0).When(
        (controllerContext, actionDescriptor) => 
            string.Equals(
                controllerContext.RouteData.GetRequiredString("controller"),
                "home",
                StringComparison.OrdinalIgnoreCase
            )
    );
    
  2. Use property injection:

    public interface IFoo { }
    public class Foo : IFoo { }
    
    public class MyFooFilter : AuthorizeAttribute
    {
        [Inject]
        public IFoo Foo { get; set; }
    }
    

    and then configure the kernel:

    kernel.Bind<IFoo>().To<Foo>();
    

    and decorate some controller/action with your custom filter:

    [MyFooFilter]
    public ActionResult Index()
    {
        return View();
    }
    


回答2:

See this question /answer here:

Setup filter attribute for dependency injection to accept params in constructor

and here

Dependency Injection with Ninject and Filter attribute for asp.net mvc