【问题标题】:Property Injection in Base Controller using Ninject 2使用 Ninject 2 在基本控制器中进行属性注入
【发布时间】:2011-03-10 09:57:12
【问题描述】:

我的 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;
    }
}

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

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

【问题讨论】:

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


    【解决方案1】:

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

    一般来说,构造函数注入是一种很好的默认方法。然而,ASP.NET MVC 的工作方式使得这更难做到(因此 FubuMVC 等)。所以属性注入是下一个最佳选择。

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

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

    • 决定要自动注入的内容。你要注入所有不具体的公开内容吗?你的内核知道的一切?除非你能对你想做的事情提出一个清晰的定义,否则注入过程可能会变得不可预测且难以理解。你最终要调试并向同事解释很多。

    • 提高效率。 Ninject 在幕后动态生成代码以使实例的激活有效(即,在遍历类时寻找[Inject] 标记,它会生成一次代码来执行该操作,然后就像您以手写方式编写一样)。

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

    但是,如果您要深入到容器中,则需要

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

    【讨论】:

    • Ruben,您能否提供一个示例,我将如何在 ServiceModule 中编写一个绑定规则,告诉 Ninject 将 ProductService 注入基本控制器的属性中?谢谢!
    • @Thomas:我从来没有做过这种性质的定制(而且我不相信这是一个好方法也不想这样做),不幸的是我无法抽出时间这样做 -抱歉......(到目前为止,我的回答似乎被认为没有价值,为什么我 - 我没有任何反馈表明我的回答已被理解或正确?)
    【解决方案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>();
        }
    }
    

    【讨论】:

    • +1 提供样本而不是像我一样漫无目的的工作做得很好!不确定从 MemberInfo 转换查找 PropertyInfo 的方式是否正确 - 也许您应该使用 is/as?此外,TryGet 将构建完整的对象,然后您将其丢弃。你想要一个 CanResolve 操作(我想不出它的名字)。在这种情况下,我认为乍一看还可以,但我个人会花几分钟时间仔细研究 .ReflectedType 的 MSDN 文档,以确定这是否完全我的意思。
    • 我认为这将是一个学习的好机会。我之所以这样做var propertyInfo = member.ReflectedType.GetProperty(member.Name); 是因为在我的测试项目中,member 原来是一个RuntimePropertyInfo,它是一个内部类。所以我只是跑了一个能想到的下一个最好的东西。我选择了kernel.TryService(Type) 而不是kernel.CanResolve(IRequest),因为它比构造一个完整的请求要简单得多。但是,我会假设ControllerInjectorHeuristic 不会表现得很好。它绝对不是生产就绪
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多