Инъекция зависимостей при построении объекта - PullRequest
2 голосов
/ 13 февраля 2012

Я создаю пользовательский ActionResult для своих контроллеров, потому что я заметил много повторяющихся кодов, которые можно использовать повторно.Это выглядит примерно так:

 public ExtendedViewResult<T> : ActionResult
 {
      protected T Model { get; set; }
      protected IModelExtender<T> Extender { get; set; }

      public ExtendedActionResult(T model, IModelExtender<T> extender)
      {
          this.Model = model;
          this.Extender = extender;
      }
 }

 public class BaseController : Controller
 {
     public ExtendedViewResult<T> ExtendedView<T>(T model)
     {
         // I need to create the result here, but how?
         var result = new ExtendedViewResult<T>(model, ???????);

         return result;
     }
 }

Проблема, с которой я столкнулся, заключается в том, что я не уверен, как создать свой объект ExtendedViewResult.Поскольку интерфейс является общим, я хочу использовать Dependency Injection для получения нужного объекта, но я не уверен, как это сделать, поскольку сам создаю объект.

Я использую Ninject и Ninject.MVC3и пакет Nuget по умолчанию создает для меня класс Bootstrapper, и когда я получаю доступ к свойству Bootstrapper.Kernel, я получаю следующее предупреждение:

Ninject.Web.Mvc.Bootstrapper.Kernel is obsolete. Do not use Ninject as Service Locator.

Если я не должен получить доступнапрямую ядро, то как я могу изменить свой код, чтобы я мог получить соответствующий конкретный класс?

EDIT
Вот недействительный код начальной загрузки.Единственный метод, который я добавил, это GetInstance ()

public static class NinjectMVC3 
{
    private static readonly Bootstrapper bootstrapper = new Bootstrapper();

    /// <summary>
    /// Starts the application
    /// </summary>
    public static void Start() 
    {
        DynamicModuleUtility.RegisterModule(typeof(OnePerRequestModule));
        DynamicModuleUtility.RegisterModule(typeof(HttpApplicationInitializationModule));
        bootstrapper.Initialize(CreateKernel);
    }

    /// <summary>
    /// Stops the application.
    /// </summary>
    public static void Stop()
    {
        bootstrapper.ShutDown();
    }

    // I ADDED THIS CODE, EVERYTHING ELSE IS AUTO-GENERATED
    // BY THE NUGET PACKAGE
    public static T GetInstance<T>()
    {
        return bootstrapper.Kernel.Get<T>();
    }

    /// <summary>
    /// Creates the kernel that will manage your application.
    /// </summary>
    /// <returns>The created kernel.</returns>
    private static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        RegisterServices(kernel);
        return kernel;
    }

    /// <summary>
    /// Load your modules or register your services here!
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    private static void RegisterServices(IKernel kernel)
    {
    }        
}

Ответы [ 2 ]

1 голос
/ 13 февраля 2012

Извините, но в реальном коде это будет сухо - я не очень много использовал ninject, но у других DI-контейнеров есть такое решение, и я уверен, что у ninject также будет эта конструкция.

Проблема в том, чточто вы строите сам объект.Когда вы действительно используете DI-контейнер и следуете IoC, в любое время вы видите, что ключевое слово new должно быть красным, а использование контейнера в качестве локатора службы - желтым.

Так как же намизбавиться от «нового», так как вам нужен новый объект?Ответ заключается в том, чтобы ваша BaseController взяла зависимость от фабрики, которая может создать ExtendedViewResult.В Autofac (мой контейнер по выбору) это было бы так же просто, как вводить Func<ExtendedViewResult>.Я был бы удивлен, если бы у Ninject не было того же самого.На самом деле, выглядит так: эта недействительная вики-страница указывает на это сообщение в блоге на Ninject.Extensions.Factory .

Так что это означает, что ваш код для контроллераможет выглядеть так:

public class ConcreteController : BaseController
 {
     private Func<Foo,ExtendedViewResult<Foo>> _factory;
     public BaseController(Func<Foo,ExtendedViewResult<Foo>> factory)
     { 
        _factory = factory;
     }

     public ExtendedViewResult<Foo> Method(Foo model)
     {            
         var result = _factory(model);    
         return result;
     }
 }

Если вы ДЕЙСТВИТЕЛЬНО хотите, чтобы универсальный метод выполнял создание в вашем базовом классе, то вам, вероятно, потребуется перейти к явному маршруту интерфейса фабрики из публикации в блоге, указанной выше.Однако с этим кодом стиля он вам в большинстве случаев не понадобится, и ваши контроллеры явно объявляют необходимые им зависимости.

0 голосов
/ 13 февраля 2012

Вы должны использовать абстрактную фабрику всякий раз, когда ваши объекты хотят создавать другие объекты.Сама абстрактная фабрика может вводиться.Я задал похожий вопрос здесь: Абстрактные фабрики при использовании каркасов внедрения зависимостей

Это действительно не должно иметь большого значения, хотя ваша фабрика является общей.

...