Asp.net mvc 2 使用Ninject 2在基本控制器中进行属性注入

Asp.net mvc 2 使用Ninject 2在基本控制器中进行属性注入,asp.net-mvc-2,ioc-container,ninject,ninject-2,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 CreateKe

我的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();
    }
}
这个代码有效。我遇到的问题是,我想从基本控制器中删除inject属性,并在Ninject ServiceModule中指定它。换句话说,我如何在ServiceModule中编写一个绑定规则,告诉Ninject将ProductService注入基本控制器中的属性


如果删除该属性,我将得到一个NullReferenceException。

基于约定的绑定存在于--一个实现了
IBindingGenerator
。不过,这主要与发现接口和服务有关

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

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

我将描述您试图做的基于约定的激活。问题在于:

  • 决定要自动注入的内容。你会把所有不具体的东西都公开吗?内核所知道的一切?除非你能对你想要做的事情给出一个清晰的定义,否则注入过程可能会变得不可预测且难以理解。最后,你会对同事进行大量的调试和解释

  • 让它更有效率。Ninject在后台动态生成代码,以使实例的激活更高效(即,在遍历类查找
    [Inject]
    标记时,它生成一次代码来执行该操作,然后就好像是直接编写的一样进行抖动)

从代码中看,OOTB没有简单的方法。看起来添加一个自定义的
iInjection
就可以了

然而,如果你要把这个深的容器,你需要

  • 停下来,看看你是否可以通过不走这条路来保持简单
  • 转到ninject邮件列表并搜索类似的内容
  • 如果你还想这样做,就发邮件到那里

  • 在Ruben Bartelink的思想基础上进行扩展,您可以创建的自定义实现

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

    向内核注册自定义实现

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

    Ruben,你能提供一个例子,说明我将如何在ServiceModule中编写一个绑定规则,告诉Ninject将ProductService注入到基本控制器的属性中吗?谢谢@托马斯:我从来没有做过这种性质的定制(因为我不相信这是一个好方法,我也不想这样做),不幸的是,我没有时间这么做-对不起。。。(到目前为止,我的答案似乎被认为价值较低,为什么我——我没有任何反馈认为我的答案已被理解或正确?+1很好的工作提供了一个样本,而不是像我一样漫无边际!不确定从MemberInfo转换属性信息的方式是否正确-也许您应该使用
    is
    /
    as
    ?另外,一个
    TryGet
    将生成一个完整的对象,然后将其丢弃。您需要一个CanResolve操作(我想不起它的名称)。在这种情况下,我相信乍一看是可以的,但我个人会花几分钟仔细阅读MSDN文档中的
    .ReflectedType
    ,以了解这是否正是我的意思。我认为这将是一个学习的好机会。我执行
    var propertyInfo=member.ReflectedType.GetProperty(member.Name)的原因
    是因为在我的测试项目中,
    成员
    原来是一个
    RuntimePropertyInfo
    ,它是一个内部类。所以我就带着a能想到的下一个最好的东西跑了。我选择了
    kernel.TryService(Type)
    而不是
    kernel.CanResolve(IRequest)
    ,因为它比构造一个完整的请求简单得多。然而,我相信,
    ControllerInjectorHeuristic
    的性能不会很好。它肯定还没有准备好生产。
    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;
        }
    }
    
    var kernel = new StandardKernel();
    kernel.Components.Add<IInjectionHeuristic, ControllerInjectionHeuristic>();
    
    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>();
        }
    }