17

I am working on a middle sized WPF application (MVVM) that should be extensible and maintainable in the future. Thus I decided to use an IoC container (Unity in this case) to keep things flexible.

However I am not sure where to place and configure Unity in a WPF application.

I guess container should be accessible globally so it should probably go to Application class. But should I make it as static property? Should I configure it in Application_Startup() event handler?

Eg:

/// <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
    }
}

This way I will be able to access container from any place in the application via static property:

App.MyUnityContainer

I guess this is one way to do it but I am not sure if there are better practices for this issue, specifically for WPF apps.

matori82
  • 3,669
  • 9
  • 42
  • 64

3 Answers3

8

Have a look at the Composition Root Pattern. What you want to do is to initialize it in your Startup event handler and forget about its existence for the rest of the application.

You are trying to implement the Service Locator Pattern, which according to many is an inferior solution to this problem.

Filippo Pensalfini
  • 1,714
  • 12
  • 16
  • How can I completely forget its existence? You'll want to resolve dependencies on the topmost level of your dependency graph, won't you? I mean, for example, a button click event handler is supposed to save `Customer` to the database, which uses `CustomerRepository`. Won't you have to resolve `CustomerRepository` in order to use it, thus need the IoC container again? – johnildergleidisson Oct 15 '12 at 21:10
  • 1
    @JoaoMilasch Topmost level? Absolutely. But why would the topmost level be a window and not the App class? In your case, you have a Window requiring a repository, which can be injected via Constructor Injection. You can then resolve the MainWindow in the Startup event of your App calling the container. – Filippo Pensalfini Oct 16 '12 at 07:27
  • Aha! You answered my question indirectly and it all makes sense now. I was thinking I needed to configure the container on the App class but the Windows would need direct access to the configured container. Instead if I do what you're suggesting, container object will only need to exist in the App class. Correct me if I'm wrong, please! :) Thanks! – johnildergleidisson Oct 16 '12 at 11:36
  • 2
    @JoaoMilasch exactly, that's the idea! If you feel like digging deeper have a look at [this book](http://www.amazon.com/Dependency-Injection-NET-Mark-Seemann/dp/1935182501), I keep recommending it because it answered a lot of questions I had about DI. – Filippo Pensalfini Oct 16 '12 at 11:57
7

Let me post what I've concluded and hopefully it'll help people out. Correct if there's anything wrong! :P

I guess we'd be looking into something like this:

/// <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;
    }
}

Note there are no globals or singletons, the container survives as long as MainWindow does and all dependencies behind this point of entry further into the composition graph are automagically resolved as long as the container knows about them.

johnildergleidisson
  • 2,087
  • 3
  • 30
  • 50
  • 1
    I think you want RegisterType instead of Register. – Jacob Brewer May 07 '14 at 21:40
  • 1
    @JoaoMilasch missing one part and (not clear for me) how is the container "promoted" to be in a main one, something similar as you can have in asp.net MVC by "GlobalConfiguration.Configuration.DependencyResolver". "Resolve" checks only if all dependencies in container has a reference. – st35ly Sep 15 '14 at 03:12
  • ment as "superior one upon all app structure" – st35ly Sep 15 '14 at 03:35
  • @stenly `Resolve` is producing the reference according to the container's configuration. By calling `RegisterType` I'm saying that for the interface `IMainWindow`, produce the object when I call `Resolve` for that interface which in this case is an instance of `MainWindow` class. `MainWindow` however has a dependency on `ISomeDependency` (see constructor). I have then also configured the container to resolve that dependency when required. It will automatically create an instance of `SomeDependencyImplementation` class and pass it to the constructor also based on my configuration. – johnildergleidisson Sep 15 '14 at 14:12
  • In this example I am placing the container in the entry point of the application. The composition graph (tree of dependencies) will be resolved by the container as long as I have provided the configuration for every single dependency there is in that particular graph. Be such configuration to create an instance of the class every time it is required (`RegisterType`) or use an existing instance (`RegisterInstance`). – johnildergleidisson Sep 15 '14 at 14:19
2

As per new version of Unity container, we have to register it's own instance as well to get it in view models via constructor injection.

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)
{
}

Now unity container would be available for us in view model and can be used to resolve.

Arul
  • 71
  • 1
  • 1