使用Ninject 2在基础控制器中进行属性注入

时间:2010-06-30 23:48:29

标签: asp.net-mvc-2 ioc-container ninject ninject-2

我在Global.aspx中有以下代码

protected override void OnApplicationStarted()
{
    AreaRegistration.RegisterAllAreas();
    RegisterRoutes(RouteTable.Routes);
    RegisterAllControllersIn(Assembly.GetExecutingAssembly());
}

protected override IKernel CreateKernel()
{
    return new StandardKernel(new ServiceModule());
}

我还有以下Ninject模块:

internal class ServiceModule : NinjectModule
{
    public override void Load()
    {
        Bind<IProductService>().To<ProductService>().InRequestScope();
    }
}

我也有一个基本控制器:

public class BaseController : Controller
{
    [Inject]
    public IProductService ProductService
    {
        get;
        set;
    }
}

此代码有效。我遇到的问题是我想从基本控制器中删除inject属性,并在Ninject ServiceModule中指定它。换句话说,我如何在ServiceModule中编写绑定规则,告诉Ninject将ProductService注入基本控制器的属性?

如果删除该属性,我将收到NullReferenceException。

2 个答案:

答案 0 :(得分:3)

基于约定的绑定存在于http://github.com/ninject/ninject.extensions.conventions中 - 一个实现IBindingGenerator。这主要与发现接口和服务有关。

通常,构造函数注入是一种很好的默认方法。然而,ASP.NET MVC的工作方式使得这更难做(因此FubuMVC等)。因此,物业注入是下一个最佳选择。

您可能会发现在OnActivation中使用Bind可能会让您做得足够多 - 如果可以的话,这是迄今为止最简单的。

我会将您尝试做的事情描述为基于约定的激活。问题是:

  • 决定你要自动注入什么。你打算注入一些不具体的公共场合吗?你的内核知道的一切?除非您能够对您想要做的事情做出清晰的定义,否则注射过程可能会变得难以预测且难以理解。你最终会调试并向同事解释很多。

  • 提高效率。 Ninject在幕后动态生成代码,使实例的激活效率很高(即,在课程中寻找[Inject]标记时,它会生成一次代码,然后像你写的一样进行搜索它很长)。

查看代码,OOTB没有简单的方法。看起来添加自定义IInjectionHeuristic就可以了。

但是,如果您深入了解容器,则需要

  1. 暂停,看看你是否可以通过不走这条路来保持简单
  2. 转到ninject邮件列表并搜索类似的内容
  3. 如果您仍想这样做,请在那里发送邮件。

答案 1 :(得分:2)

通过Ruben Bartelink扩展您的想法,您可以创建IInjectionHeuristic的自定义实现。

public class ControllerInjectionHeuristic : NinjectComponent, IInjectionHeuristic
{
    private readonly IKernel kernel;

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

    public bool ShouldInject(MemberInfo member)
    {
        if (member.ReflectedType != typeof(BaseController))
        {
            return false;
        }

        var propertyInfo = member.ReflectedType.GetProperty(member.Name);
        object service = kernel.TryGet(propertyInfo.PropertyType);

        return service != null;
    }
}

ControllerInjectionHeuristic会在BaseController上注入内核能够解析服务的任何属性(服务)。

在内核中注册自定义实现。

var kernel = new StandardKernel();
kernel.Components.Add<IInjectionHeuristic, ControllerInjectionHeuristic>();

该问题的另一个解决方案是使用OnActivation。 (此解决方案未经测试,但它应该让您了解如何继续)。

public class ControllerModule : NinjectModule
{
    public override void Load()
    {
        // Get all controller types. You could use
        // Ninject.Extensions.Conventions.
        IEnumerable<Type> controllerTypes = null;
        foreach (var controllerType in controllerTypes)
        {
            Bind(controllerType).ToSelf().InRequestScope()
                .OnActivation(ControllerActivation);
        }
    }

    private static void ControllerActivation(IContext context, object obj)
    {
        var controller = obj as BaseController;
        if (controller == null)
        {
            return;
        }

        controller.ProductService = context.Kernel.Get<IProductService>();
    }
}