如何使用Ninject将通用接口注入MVC​​控制器

时间:2017-03-05 07:09:23

标签: c# asp.net-mvc dependency-injection ninject

我有以下情况:

  • 界面:

    public interface ITest<T> where T:class
     {
        void Delete(T item);
     }
    
  • 抽象实现:

     public abstract class Test<T>:ITest<T> where T:class 
        {
            private readonly ApplicationDbContext _context;
    
            protected Test(ApplicationDbContext context){
            _context=context;
            }
            public void Delete(T item) { }
        }
    
  • 最后一堂课:

    public class RepoTest:Test<FirstEntity>
    {
       public void DoSomething() { }
    }
    

我有一个MVC控制器,看起来像这样:

 public abstract class MyController<T>:Controller where T:class 
    {
        private readonly ITest<T> _test;
        protected MyController(ITest<T> test)
        {
            _test = test;
        }
    }

对于每个实体,我创建一个继承自MyController的控制器,并基于实体我希望ninject注入特定的类。

为此,我尝试使用此绑定:

kernel.Bind(typeof(ITest<>)).To(typeof(Test<>)).InRequestScope();

           kernel.Bind(x=>x.FromAssemblyContaining(typeof(Test<>))
           .SelectAllClasses()
           .InheritedFrom(typeof(Test<>))
           .BindToSelf());

不幸的是,我得到了这样的错误:

  

激活ITest {工具}时出错   没有匹配的绑定可用,并且该类型不可自绑定。   激活路径:    2)将依赖项ITest {Tool}注入到ToolsController类型的构造函数的参数测试中    1)对ToolsController的请求

     

建议:1)确保您已为其定义了绑定   ITEST {}工具。 2)如果在模块中定义了绑定,请确保   模块已加载到内核中。 3)确保你没有   不小心创建了多个内核。 4)如果你正在使用   构造函数参数,确保参数名称匹配   构造函数参数名称。 5)如果您使用的是自动模块   加载,确保搜索路径和过滤器正确无误。

如何告诉Ninject,在实体类型上注入类?

1 个答案:

答案 0 :(得分:1)

目前编写的代码无法正常工作。

您有两种选择:

  1. 使用通用:
  2. 因为您的控制器期望绑定到ITest<T>abstract的{​​{1}}无法实例化。

    你必须制作一个具体但通用的类Test<T>并为Test<T>添加一个自动生效的绑定。

    1. 使用Reflection在绑定时找到正确的类型,例如:
    2. 重要!!!删除两个ApplicationDbContext来电。

      kernel.Bind()

      注意:方法2目前假设所有模型和 // this will find classes which, like RepoTest, are derived from Test<> var allDerivedTypes = typeof(Test<>).Assembly.GetExportedTypes().Where(x => x.BaseType.IsGenericType && x.BaseType.GetGenericTypeDefinition() == typeof(Test<>)).ToList(); // ideally, you'd find some way to constrain all your models. // what you need for this foreach is all of the entities that can be present in things like RepoTest foreach(var t in typeof(Tool).Assembly.GetExportedTypes()) { // For each entity, get a runtime representation of Test<Entity> var targetType = typeof(Test<>).MakeGenericType(t); // Check if there is a class derived from Test<Entity> var potentiallyPresentImplementation = allDerivedTypes.FirstOrDefault(x => targetType == x.BaseType); // here you might want to decide how to handle multiple instances of the same generic base // Found one, so bind it if(potentiallyPresentImplementation != null) { kernel.Bind(targetType ).To(potentiallyPresentImplementation ).InRequestScope(); } } 衍生物都是一个可分辨的。如果不是这种情况,您需要添加一点反射魔法来检查所有引用的组件。

      此后,控制器将注入Test<>。虽然老实说,方法1.更好:)