Вопрос по wpf – Где разместить и настроить контейнер IoC в приложении WPF?

15

Я работаю над приложением среднего размера WPF (MVVM), которое должно быть расширяемым и обслуживаемым в будущем. Поэтому я решил использовать контейнер IoC (в данном случае Unity), чтобы сохранить гибкость.

Однако я не уверен, где разместить и настроить Unity в приложении WPF.

Я предполагаю, что контейнер должен быть доступен глобально, поэтому он, вероятно, должен перейти в класс Application. Но я должен сделать это как статическое свойство? Должен ли я настроить его в обработчике событий Application_Startup ()?

Например:

/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
    public static UnityContainer MyUnityContainer;


    private void Application_Startup(object sender, StartupEventArgs e)
    {
        // instantiate and configure Unity
    }
}

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

App.MyUnityContainer

Я думаю, что это один из способов сделать это, но я не уверен, есть ли лучшие методы для этой проблемы, особенно для приложений WPF.

Ваш Ответ

3   ответа
6

что я пришел к выводу, и, надеюсь, это поможет людям. Исправьте, если что-то не так! :П

Я предполагаю, что мы будем рассматривать что-то вроде этого:

/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
    private void Application_Startup(object sender, StartupEventArgs e)
    {
        UnityContainer myUnityContainer = new UnityContainer();
        //make sure your container is configured
        myUnityContainer.RegisterType<ISomeDependency, SomeDependencyImplementation>();
        myUnityContainer.RegisterType<IMainWindow, MainWindow>();

        myUnityContainer.Resolve<IMainWindow>().Show();
    }
}

public partial class MainWindow : Window, IMainWindow
{
    private ISomeDependency _someDependency;

    public MainWindow(ISomeDependency someDependency)
    {
        _someDependency = someDependency;
    }
}

Обратите внимание, что глобалов и синглетов не существует, контейнер сохраняется до тех пор, пока это делает MainWindow, и все зависимости за этой точкой входа далее в составной граф автоматически разрешаются, пока контейнер знает о них.

Спасибо за исправление @JacobBrewer
@JoaoMilasch пропустил одну часть и (как мне не ясно), как продвигается контейнер & quot; чтобы быть в основном, что-то похожее, что вы можете иметь в asp.net MVC по "GlobalConfiguration.Configuration.DependencyResolver". & Quot; Resolve & Quot; проверяет только, есть ли ссылка на все зависимости в контейнере.
Я думаю, что вы хотите RegisterType вместо Register.
как «превосходящий по всем структурам приложения»;
@stenlyResolve производит ссылку в соответствии с конфигурацией контейнера. По телефонуRegisterType Я говорю это для интерфейсаIMainWindow, производить объект, когда я звонюResolve для этого интерфейса, который в данном случае является примеромMainWindow учебный класс.MainWindow Однако имеет зависимость отISomeDependency (см. конструктор). Затем я также настроил контейнер для разрешения этой зависимости, когда это необходимо. Это автоматически создаст экземплярSomeDependencyImplementation Класс и передать его конструктору также на основе моей конфигурации.
8

Композиция Root Pattern, Что вы хотите сделать, это инициализировать его в своем обработчике события Startup и забыть о его существовании для остальной части приложения.

Вы пытаетесь реализоватьШаблон сервисного локаторакоторый по мнению многихявляется худшим решением к этой проблеме.

Как я могу полностью забыть его существование? Вы хотите разрешить зависимости на самом верхнем уровне вашего графика зависимостей, не так ли? Я имею в виду, например, обработчик события нажатия кнопки должен сохранитьCustomer в базу данных, которая используетCustomerRepository, Вы не должны решитьCustomerRepository для того, чтобы использовать его, нужно ли снова контейнер IoC?
Ага! Вы ответили на мой вопрос косвенно, и теперь все это имеет смысл. Я думал, что мне нужно настроить контейнер в классе App, но Windows потребуется прямой доступ к настроенному контейнеру. Вместо этого, если я сделаю то, что вы предлагаете, контейнерный объект должен будет существовать только в классе App. Поправьте меня, если я ошибаюсь, пожалуйста! :) Спасибо!
@JoaoMilasch Самый высокий уровень? Абсолютно. Но почему верхний уровень - это окно, а не класс App? В вашем случае у вас есть окно, требующее хранилища, которое может быть введено с помощью Constructor Injection. Затем вы можете разрешить MainWindow в событии Startup вашего приложения, вызывающего контейнер.
@JoaoMilasch точно, это идея! Если вы хотите копать глубже, взгляните наthis bookЯ продолжаю рекомендовать его, потому что он ответил на многие мои вопросы о DI.
1

мы должны также зарегистрировать его собственный экземпляр, чтобы получить его в моделях представления посредством внедрения конструктора.

App.xaml.cs file:

protected override void OnStartup(StartupEventArgs e)
{
       var unityIoC = new UnityContainer();
       unityIoC.RegisterTypes(AllClasses.FromAssembliesInBasePath(), WithMappings.FromMatchingInterface, WithName.Default);
       unityIoC.RegisterInstance(typeof(IUnityContainer), unityIoC);
}

View Model class

[InjectionConstructor]
public MyViewModel(IUnityContainer container)
{
}

Теперь единый контейнер будет доступен для нас в виде модели и может быть использован для разрешения.

Похожие вопросы