18

当谈到 DI 和 ninject 时,我是一个新手,我正在为实际注射应该何时发生以及如何开始绑定而苦苦挣扎。

我已经在我的 Web 应用程序中使用它并且在那里工作正常,但现在我想在类库中使用注入。

假设我有这样的课程:

public class TestClass
{
    [Inject]
    public IRoleRepository RoleRepository { get; set; }
    [Inject]
    public ISiteRepository SiteRepository { get; set; }
    [Inject]
    public IUserRepository UserRepository { get; set; }

    private readonly string _fileName;

    public TestClass(string fileName)
    {
        _fileName = fileName;
    }

    public void ImportData()
    {
        var user = UserRepository.GetByUserName("myname");
        var role = RoleRepository.GetByRoleName("myname");
        var site = SiteRepository.GetByID(15);
        // Use file etc
    }

}

我想在这里使用属性注入,因为我需要在构造函数中传入一个文件名。我是否正确地说如果我需要传入构造函数参数,我不能使用构造函数注入?如果我可以使用带有附加参数的构造函数注入,我该如何传递这些参数?

我有一个由 Test 类使用的控制台应用程序,如下所示:

class Program
{
    static void Main(string[] args)
    {
        // NinjectRepositoryModule Binds my IRoleRepository etc to concrete
        // types and works fine as I'm using it in my web app without any
        // problems
        IKernel kernel = new StandardKernel(new NinjectRepositoryModule());

        var test = new TestClass("filename");

        test.ImportData();
    }
}

我的问题是,当我调用test.ImportData()我的存储库时,它们是空的 - 没有任何东西注入它们。我尝试创建另一个模块并调用

Bind<TestClass>().ToSelf();

因为我认为这可能会解决所有注入属性,TestClass但我无处可去。

我确定这是一个微不足道的问题,但我似乎无法找到解决方法。

4

2 回答 2

18

您是直接 newing TestClass,Ninject 无法拦截 - 请记住,没有像代码转换这样的魔法拦截您new的 s 等。

你应该这样做kernel.Get<TestClass>

如果做不到这一点,你可以在它之后注入 newkernel.Inject( test);

我认为wiki中有一篇文章谈论InjectvsGet等。

请注意,一般来说,直接GetInject调用是服务位置的“做错了”的味道,这是一种反模式。对于您的 Web 应用程序,NinjectHttpModuleandPageBase是拦截对象创建的钩子 - 在其他样式的应用程序中也有类似的拦截器/逻辑位置可以拦截。

重新您的Bind<TestClass>().ToSelf(),通常是一个StandardKernelhas ImplicitSelfBinding = true,这会使它变得不必要(除非您想将其 Scope 影响为 以外的东西.InTransientScope())。

最后一个风格点:-您正在使用属性注入。这很少有充分的理由,因此您应该改用构造函数注入。

并且一定要购买@Mark Seemann 在.NET 中的依赖注入,他在这里有很多优秀的帖子,涵盖了依赖注入领域及其周围的许多重要但微妙的考虑因素。

于 2009-08-18T16:03:55.017 回答
7

好的,

我已经找到了我需要的方法,部分感谢您的评论 Ruben。我创建了一个新模块,它基本上保存了我在类库中使用的配置。在这个模块中,我可以使用占位符接口进行绑定,也可以将构造函数参数添加到 CustomerLoader。下面是来自虚拟控制台应用程序的代码,用于演示这两种方式。

这可能有助于其他人开始使用 Ninject!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ninject.Core;
using Ninject.Core.Behavior;

namespace NinjectTest
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var kernel = new StandardKernel(new RepositoryModule(), new  ProgramModule());            
            var loader = kernel.Get<CustomerLoader>();
            loader.LoadCustomer();
            Console.ReadKey();
        }
    }

    public class ProgramModule : StandardModule
    {
        public override void Load()
        {
            // To get ninject to add the constructor parameter uncomment the line below
            //Bind<CustomerLoader>().ToSelf().WithArgument("fileName", "string argument file name");
            Bind<LiveFileName>().To<LiveFileName>();
        }
    }

    public class RepositoryModule : StandardModule
    {
        public override void Load()
        {
            Bind<ICustomerRepository>().To<CustomerRepository>().Using<SingletonBehavior>();
        }
    }

    public interface IFileNameContainer
    {
        string FileName { get; }
    }
    public class LiveFileName : IFileNameContainer
    {
        public string FileName
        {
            get { return "live file name"; }
        }
    }


    public class CustomerLoader
    {
        [Inject]
        public ICustomerRepository CustomerRepository { get; set; }
        private string _fileName;

        // To get ninject to add the constructor parameter uncomment the line below
        //public CustomerLoader(string fileName)
        //{
        //    _fileName = fileName;
        //}
        public CustomerLoader(IFileNameContainer fileNameContainer)
        {
            _fileName = fileNameContainer.FileName;
        }

        public void LoadCustomer()
        {
            Customer c = CustomerRepository.GetCustomer();
            Console.WriteLine(string.Format("Name:{0}\nAge:{1}\nFile name is:{2}", c.Name, c.Age, _fileName));
        }
    }

    public interface ICustomerRepository
    {
        Customer GetCustomer();
    }
    public class CustomerRepository : ICustomerRepository
    {
        public Customer GetCustomer()
        {
            return new Customer() { Name = "Ciaran", Age = 29 };
        }
    }
    public class Customer
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
}
于 2009-08-18T22:23:45.313 回答