【问题标题】:How to use Ninject's Named bindings in Simple Injector?如何在 Simple Injector 中使用 Ninject 的命名绑定?
【发布时间】:2018-11-23 20:53:20
【问题描述】:

我有一个使用 Ninject for DI 的 MVC 应用程序,我计划将其迁移到 Simple Injector。但是我找不到任何替代方法来用 Simple Injector 替换 Ninject 的命名绑定。

绑定:

    kernel.Bind<IStudent>().To<Student1>().Named("Senior");
    kernel.Bind<IStudent>().To<Student2>().Named("Junior");
    kernel.Bind<IStudent>().To<Student3>().Named("Junior");

控制器:

public class StudentController
{
  private readonly IEnumerable<IStudent> _seniors;
  private readonly IEnumerable<IStudent> _juniors;
  public StudentController([named("Senior")] IEnumerable<IStudent> seniors,[named("Junior")] IEnumerable<IStudent> juniors)
  {
    _seniors=seniors;
    _juniors=juniors;
  }
}

我提到了几个链接How to use Ninject's Named bindings in Simple Injector。但是运气不好。

【问题讨论】:

    标签: c# dependency-injection ninject simple-injector ninject.web.mvc


    【解决方案1】:

    有很多选择:

    选项 1:使用 [named] 属性

    要实现这一点,您必须重新创建 NamedAttribute,因为这不是 Simple Injector 中存在的东西,for good reason

    您可以对学生集合进行以下两种条件注册:

    container.RegisterConditional<IEnumerable<IStudent>>(
        container.Collection.CreateRegistration<IStudent>(
            typeof(Student1)),
        c => c.Consumer.Target.GetCustomAttribute<namedAttribute>()?.Name == "Senior");
    
    container.RegisterConditional<IEnumerable<IStudent>>(
        container.Collection.CreateRegistration<IStudent>(
            typeof(Student2),
            typeof(Student3)),
        c => c.Consumer.Target.GetCustomAttribute<namedAttribute>()?.Name == "Junior");
    

    每个条件注册都为IStudent 集合包装一个Registration。谓词过滤目标,在本例中为构造函数参数,以获取其 namedAttribute 的名称。

    选项 2:没有命名属性,通过检查参数名称

    然而,一个更简单的选择是完全放弃命名属性,只根据构造函数参数的名称进行过滤:

    container.RegisterConditional<IEnumerable<IStudent>>(
        container.Collection.CreateRegistration<IStudent>(
            typeof(Student1)),
        c => c.Consumer.Target.Name == "seniors");
    
    container.RegisterConditional<IEnumerable<IStudent>>(
        container.Collection.CreateRegistration<IStudent>(
            typeof(Student2),
            typeof(Student3)),
        c => c.Consumer.Target.Name == "juniors");
    

    这种注册方式与选项 1 几乎相同,但现在我们根据参数的实际名称进行过滤,而不是根据其属性。

    选项 3:手动连接 StudentController。

    一个更简单的选择是从自动接线StudentsController 恢复为手动接线,如下所示:

    var seniors = container.Collection.Create<IStudent>(typeof(Student1));
    var juniors = container.Collection.Create<IStudent>(typeof(Student2), typeof(Student3));
    container.Register(() => new StudentController(seniors: seniors, juniors: juniors));
    

    这里我们请求Container创建两个学生集合,并为StudentsController创建注册,两个集合都被注入其中。

    请注意,在 Simple Injector 集合是流。这意味着对Collection.Create 的调用确实创建学生实例,只是对迭代时将产生学生实例的流的引用。这意味着,可以在应用程序启动时创建流,同时保留注册的生活方式。

    另外请注意,如果您调用RegisterMvcControllers,您将不得不覆盖此控制器类的现有注册。 This page 展示了如何做到这一点。

    选项 4:更改设计。使“级别”成为 IStudent 的属性。在控制器内部过滤。

    您可以决定以简化注册的方式更改您的设计。这是否更好在很大程度上取决于上下文,所以请持保留态度。但是,当您将 Level 属性或类似属性添加到表示学生是否为大四学生的 IStudent 接口,并基于控制器内部进行过滤时,您的注册非常大大简化为以下内容:

    container.Collection.Register<IStudent>(typeof(Student1).Assembly);
    

    在这里,我们使用自动注册来搜索所有学生实现并将它们全部注册到一个集合中。

    在这种情况下,StudentController 将保留一个构造函数参数,但您显然将过滤责任从Composition Root 移到了控制器中。

    public class StudentController
    {
        private readonly IEnumerable<IStudent> _students;
    
        public StudentController(IEnumerable<IStudent> students)
        {
            _students = students;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多