Подтвердить что ты не робот

Ninject - как и когда вводить

Я новичок, когда дело доходит до DI и ninject, и я немного борюсь о том, когда произойдет фактическая инъекция, и как начать связывание.

Я использую его уже в своем веб-приложении, и он отлично работает там, но теперь я хочу использовать инъекции в библиотеке классов.

Скажем, у меня есть класс вроде этого:

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, но я никуда не буду.

Я уверен, что это тривиальная проблема, но я просто не могу понять как это сделать.

4b9b3361

Ответ 1

Вы непосредственно вносите TestClass, который у Ninject не имеет возможности перехватить - помните, что нет никакой магии, как преобразование кода, перехватывающее ваш new и т.д.

Вместо этого вы должны делать kernel.Get<TestClass>.

В противном случае вы можете ввести его после new с помощью kernel.Inject( test);

Я думаю, что есть статья в вики, в которой говорится о Inject vs Get и т.д.

Обратите внимание, что в общем случае прямые вызовы Get или Inject - это неправильный запах местоположения службы, который является антипаттерном. В случае вашего веб-приложения NinjectHttpModule и PageBase - это крюк, который перехватывает создание объекта - существуют аналогичные перехватчики/логические места для перехвата в других стилях приложения.

Re Bind<TestClass>().ToSelf(), обычно StandardKernel имеет ImplicitSelfBinding = true, что сделало бы это ненужным (если вы не хотите влиять на его область действия как нечто отличное от .InTransientScope()).

Конечная точка стиля: - вы используете инъекцию свойств. Для этого редко бывают веские причины, поэтому вместо этого вы должны использовать инъекцию конструктора.

И действительно, купите Injection Dependency в .NET от @Mark Seemann, у которого есть стопки отличных сообщений, которые здесь охватывают множество важных, но тонкие соображения в области Инъекции зависимостей и вокруг нее.

Ответ 2

OK

Я узнал, как делать то, что мне нужно, частично благодаря вашим комментариям Рубена. Я создал новый модуль, который в основном содержит конфигурацию, которую я использую в библиотеке классов. Внутри этого модуля я могу либо Связывание с использованием интерфейса-заполнителя, либо я могу добавить параметр конструктора в 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; }
    }
}