ReactiveUi: How can I replace the default IViewLocator when using AutoFac?

597 Views Asked by At

High!

I am trying to replace the default IViewLocator of ReactiveUi/Splat in WPF. I am using AutoFac as container.

My goal is very simple: ReactiveUi/Splat should use my custom implementation of IViewLocator when resolving a view for view model.

I really read every availabe tutorial and stackoverflow thread, but nothing helped.

Currently I do the following while bootstrapping: (I tried many different things...)

namespace MDM
{
    public static class Bootstrapper
    {
        private static AutofacDependencyResolver? Locator;
        private static IContainer? Container;

        public static void Register()
        {
            Splat.Locator.CurrentMutable.InitializeSplat();
            Splat.Locator.CurrentMutable.InitializeReactiveUI();
            Splat.Locator.CurrentMutable.RegisterConstant<IViewLocator>(new ViewLocator());

            var builder = new ContainerBuilder();

            builder.RegisterType<MainWindowView>().As<IViewFor<MainWindowViewModel>>().SingleInstance();
            builder.RegisterType<EinstellungenView>().As<IViewFor<EinstellungenViewModel>>().SingleInstance();
            builder.RegisterType<MainWindowViewModel>().AsSelf().SingleInstance();
            builder.RegisterType<EinstellungenViewModel>().AsSelf().SingleInstance();

            Locator = builder.UseAutofacDependencyResolver();
            builder.RegisterInstance(Locator);

            Locator.InitializeReactiveUI();
            Splat.Locator.SetLocator(Locator);

            Container = builder.Build();

            Locator.SetLifetimeScope(Container);

        }

        public static T Resolve<T>() where T : class
        {
            return Container!.Resolve<T>();
        }

    }
}

While debugging the following line of code in my IViewLocator is never hit:

public IViewFor? ResolveView<T>(T viewModel, string? contract = null)
{

}

So my question is: What do I need to do while bootstrapping, to tell ReactiveUi to use my IViewLocator?

1

There are 1 best solutions below

2
On BEST ANSWER

If you decide to drop Splat (the IoC container used by ReactiveUI) and use Autofac, then you must go with it, especially when registering services.
Once you have registered a custom IoC container (properly), you shouldn't use Splat anymore to resolve any dependencies. Although Splat will redirect service requests to the Autofac container, I recommend against mixing the APIs.

var containerBuilder = new ContainerBuilder();

// TODO::Register application's dependencies with Autofac

/* Configure Splat to use Autofac */
var autofacResolver = containerBuilder.UseAutofacDependencyResolver();
containerBuilder.RegisterInstance(autofacResolver);
autofacResolver.InitializeReactiveUI();

// AFTER configuring the IoC redirect, register the Splat service overrides
containerBuilder.RegisterType<ViewLocator>()
  .As<IViewLocator>()
  .SingleInstance();

var container = containerBuilder.Build(); 
autofacResolver.SetLifetimeScope(container);

Don't use the Service Locator anti-pattern. The IoC container should not be distributed across the application. Neither as injected reference nor as static reference.
Use the Abstract Factory pattern instead.

For this reason, IViewLocator.ResolveView must use factories instead of the static Resolve method that you have implemented in your Bootstrapper.