I am trying to override the DI container used in Avalonia and ReactiveUI with Autofac. So far I have tried following the instructions in the Splat.Autofac
repository, but I can't get Avalonia to work.
As a working example, I took the HelloWorld example from the ReactiveUI.Samples repository.
I could think of two places to override Splat. In App.xaml.cs
in the OnFrameworkInitializationCompleted
method:
using System.Reflection;
using Autofac;
using Avalonia;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
using Avalonia.Threading;
using ReactiveUI;
using Splat;
using Splat.Autofac;
namespace ReactiveAvalonia.HelloWorld {
public class App : Application {
public override void Initialize() {
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
// Build a new Autofac container.
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).AsImplementedInterfaces();
// Use Autofac for ReactiveUI dependency resolution.
// After we call the method below, Locator.Current and
// Locator.CurrentMutable start using Autofac locator.
AutofacDependencyResolver resolver = new AutofacDependencyResolver(builder);
Locator.SetLocator(resolver);
// These .InitializeX() methods will add ReactiveUI platform
// registrations to your container. They MUST be present if
// you *override* the default Locator.
Locator.CurrentMutable.InitializeSplat();
Locator.CurrentMutable.InitializeReactiveUI();
var container = builder.Build();
resolver.SetLifetimeScope(container);
}
}
}
But when running this, the startup fails with the following exception:
System.ArgumentException: 'Don't know how to detect when ReactiveAvalonia.HelloWorld.MainView is activated/deactivated, you may need to implement IActivationForViewFetcher'
My other idea was to do the overriding in Program.cs
's Main
:
using System.Reflection;
using Autofac;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Logging.Serilog;
using Avalonia.ReactiveUI;
using Avalonia.Threading;
using ReactiveUI;
using Splat;
using Splat.Autofac;
namespace ReactiveAvalonia.HelloWorld {
// You may want to start here:
// https://reactiveui.net/docs/getting-started/
class Program {
// http://avaloniaui.net/docs/reactiveui/
// https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes
public static AppBuilder BuildAvaloniaApp() {
return AppBuilder
.Configure<App>()
.UseReactiveUI()
.UsePlatformDetect()
.LogToDebug();
}
private static void AppMain(Application app, string[] args) {
app.Run(new MainView());
}
public static void Main(string[] args) {
// Build a new Autofac container.
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).AsImplementedInterfaces();
// Use Autofac for ReactiveUI dependency resolution.
// After we call the method below, Locator.Current and
// Locator.CurrentMutable start using Autofac locator.
AutofacDependencyResolver resolver = new AutofacDependencyResolver(builder);
Locator.SetLocator(resolver);
// These .InitializeX() methods will add ReactiveUI platform
// registrations to your container. They MUST be present if
// you *override* the default Locator.
Locator.CurrentMutable.InitializeSplat();
Locator.CurrentMutable.InitializeReactiveUI();
var container = builder.Build();
resolver.SetLifetimeScope(container);
BuildAvaloniaApp().Start(AppMain, args);
}
}
}
But this fails with another exception:
System.Exception: 'Container has already been built and the lifetime scope set, so it is not possible to modify it anymore.'
What can I do to get this to work?