在MVC3中的抽象基本控制器中使用Ninject的属性注入没有属性

时间:2011-06-29 15:43:38

标签: asp.net-mvc-3 ninject ninject-2

我有以下代码:

public abstract class BaseController : Controller
{
    public IUserService UserService { get; set; }
}

我的所有控制器都从这个基本控制器继承。我首先使用以下代码在Ninject中配置它:

kernel.Bind<BaseController>()
      .ToSelf()
      .WithPropertyValue("UserService", x => x.Kernel.GetService(typeof(IUserService)));

这不起作用。我认为这是因为BaseController是一个抽象类(请确认我的假设)。所以我继续将配置修改为:

kernel.Bind<HomeController>()
      .ToSelf()
      .WithPropertyValue("UserService", x => x.Kernel.GetService(typeof(IUserService)));

这确实有效。一个小缺点是我现在必须以相同的方式配置每个控制器。

由于我在ASP.NET MVC 3项目中也设置了DependencyResolver,我还可以删除上面的Ninject配置并修改我的基本控制器,如下所示:

    public IUserService UserService
    {
        get
        {
            return DependencyResolver.Current.GetService<IUserService>();
        }
    }

与使用DependencyResolver方法相比,使用流畅配置有什么好处?这个比那个好吗?哪种方法被认为是更好的做法?

值得一提的是,我不想在我的基本控制器中进行构造函数注入。

3 个答案:

答案 0 :(得分:2)

在MVC中更好的做法是在属性注入上使用构造函数注入。你为什么这样做出选择?

使用构造函数注入,您声明构造函数中的所有依赖项都是必需的,以便该类完成其工作。

属性注入意味着依赖关系是可选的,或者存在本地默认实现,因此即使您不自己提供必要的实现,所有实现也都会有效。 / p>

你应该真的知道你正在使用Property注入做什么,或者你别无选择,所以更安全的方法是依赖构造函数注入。

现在我会告诉你我的观点。其他人可能有其他意见。

DependencyResolver在MVC 3中引入了“方便”的服务位置,但对我而言,它是一个常规的服务定位器,对我来说也是一个反模式http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx。我不使用它,因为我不喜欢它,使用它没有任何好处。 我更喜欢像以前一样使用我的控制器工厂,并通过构造函数传递依赖项。

更多 IDependencyResolver 与某些IoC容器存在somme问题(我不知道Ninject是否属于这种情况)。您可以在此处阅读更多内容:http://mikehadlow.blogspot.com/2011/02/mvc-30-idependencyresolver-interface-is.html

答案 1 :(得分:2)

如果您需要在每个控制器中使用相同的依赖项,那么您的设计中似乎存在问题。您最有可能在基本控制器中处理某种横切问题。在这种情况下,做性能注射只是治疗症状而不是治愈疾病。这应该由一个方面(例如过滤器或拦截器)来处理,这样你就不必用不属于那里的东西来污染你的控制器。

答案 2 :(得分:0)

有许多方法可以给他们说的猫皮肤。您可以使用基于约定的约束.WithPropertyValue().OnActivaction()(如here所述)。

public class ControllerModule : NinjectModule
{
    public override void Load()
    {
        // Get all controller types derived from the base controller.
        IEnumerable<Type> controllerTypes = // ...
        foreach (var controllerType in controllerTypes)
        {
            Bind(controllerType).ToSelf().InRequestScope()
                .WithPropertyValue(...);
        }
    }
 }

您可以创建自己的IInjectionHeuristic界面自定义实现,如here所述,或您自己的IControllerActivator界面自定义实现。

public class CustomNinjectControllerActivator : IControllerActivator
{
    private readonly IKernel kernel;

    public CustomNinjectControllerActivator(IKernel kernel)
    {
        this.kernel = kernel;
    }

    public IController Create(RequestContext context, Type controllerType)
    {
        var baseController = kernel.TryGet(controllerType) as BaseController;
        if (baseController == null)
        {
            return null;
        }

        baseController.UserService = kernel.Get<IUserService>();
        return baseController;
    }
}

哎呀,如果你习惯使用它,你甚至可以使用服务定位器模式。

public IUserService UserService
{
    get { return DependencyResolver.Current.GetService<IUserService>(); }
}

您应该选择最容易实施,测试和维护的解决方案,当然还要提供所需的行为。