2012-02-13 3 views
2

Я создаю пользовательский 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.Kernel я получаю следующее предупреждение:

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

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

EDIT
Вот Ninject код Загрузчик. Единственный метод, который я добавил это 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) 
    { 
    }   
} 

ответ

1

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

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

Итак, как нам избавиться от «нового», так как вам нужен новый объект? Ответ должен состоять в том, чтобы ваш BaseController зависел от фабрики, которая может создать ExtendedViewResult. В Autofac (мой контейнер выбора), это было бы так же просто, как вставить Func<ExtendedViewResult>. Я был бы удивлен, если у Ninject не будет такого же. На самом деле, выглядит так: this ninject wiki page указывает на это blog post on 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

Проблема с передачей этого в конкретный контроллер заключается в том, что у меня может быть 10 различных методов действий, которые имеют разные модели. Для этого мне нужно было бы передать 10 различных зависимостей Func для моего контроллера, что не похоже на лучший вариант. – Dismissile

+0

@ Disismile В этом случае я бы рекомендовал создать завод самостоятельно. Я не думаю, что ninject может автозаписывать фабрики на основе открытого общего, а параметр конструктора просто усложняет работу.Если вы обнаружите, что это возможно, пожалуйста, обновите свой вопрос, отредактируйте этот ответ или ответьте на свой вопрос - мне бы хотелось увидеть результат. Мой контейнер выбора - AutoFac, и я думаю, для этого потребуется некоторое количество мастеров регистрации. –

+0

@ Disismile относительно вашей собственной фабрики, помните, что вы можете зависеть от IResolutionRoot и позвонить. Получите это. В простом случае вы можете просто зависеть от IResolutionRoot в вашем BaseController. Это в значительной степени используется ServiceLocator, но вы запрашиваете локатор как зависимость, а не находите его самостоятельно. –

0

Вы должны использовать абстрактную фабрику в любое время ваши объекты хотят создавать другие объекты. Сама абстрактная фабрика может быть введена. Я задал аналогичный вопрос здесь: Abstract factories when using dependency injection frameworks

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

Смежные вопросы