如何在 Avalonia.ReactiveUI 中使用 Autofac 作为 DI 容器?
Posted
技术标签:
【中文标题】如何在 Avalonia.ReactiveUI 中使用 Autofac 作为 DI 容器?【英文标题】:How to use Autofac as DI container in Avalonia.ReactiveUI? 【发布时间】:2021-03-14 13:16:45 【问题描述】:我正在尝试使用 Autofac 覆盖在 Avalonia 和 ReactiveUI 中使用的 DI 容器。到目前为止,我已经尝试关注instructions in the Splat.Autofac
repository,但我无法让 Avalonia 工作。
作为一个工作示例,我采用了HelloWorld example from the ReactiveUI.Samples 存储库。
我可以想到两个地方来覆盖 Splat。在App.xaml.cs
中OnFrameworkInitializationCompleted
方法中:
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);
但是在运行时,启动失败并出现以下异常:
System.ArgumentException: '不知道如何检测 ReactiveAvalonia.HelloWorld.MainView 何时激活/停用,您可能需要实现 IActivationForViewFetcher'
我的另一个想法是在Program.cs
的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);
但这失败了,还有一个例外:
System.Exception: '容器已经构建并且生命周期范围设置,所以不能再修改它。'
我该怎么做才能让它发挥作用?
【问题讨论】:
【参考方案1】:通常,Avalonia 文档会告诉您使用 AppBuilder
上的 UseReactiveUI
extension method 才能使用 ReactiveUI。它的作用是将一些 Avalonia 组件注册到 DI 容器:
public static TAppBuilder UseReactiveUI<TAppBuilder>(this TAppBuilder builder)
where TAppBuilder : AppBuilderBase<TAppBuilder>, new()
return builder.AfterPlatformServicesSetup(_ =>
RxApp.MainThreadScheduler = AvaloniaScheduler.Instance;
Locator.CurrentMutable.RegisterConstant(new AvaloniaActivationForViewFetcher(), typeof(IActivationForViewFetcher));
Locator.CurrentMutable.RegisterConstant(new AutoDataTemplateBindingHook(), typeof(IPropertyBindingHook));
);
对于问题中的两种解决方案,出现问题的可能方式有两种:
在App
中设置 Autofac
当您在 OnFrameworkInitializationCompleted
中设置 Autofac 时,这会发生在 UseReactiveUI
中的注册设置完成之后,基本上会覆盖它们。
如果您在覆盖 DI 容器后再次添加这些代码行,应用程序将启动:
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();
Locator.CurrentMutable.RegisterConstant(new AvaloniaActivationForViewFetcher(), typeof(IActivationForViewFetcher));
Locator.CurrentMutable.RegisterConstant(new AutoDataTemplateBindingHook(), typeof(IPropertyBindingHook));
RxApp.MainThreadScheduler = AvaloniaScheduler.Instance;
var container = builder.Build();
resolver.SetLifetimeScope(container);
在Main
中设置 Autofac
在这里,我们已经在 Avalonia 尝试注册其组件之前覆盖了 DI 容器,此时,Autofac 容器已经创建,并且它是只读的,这会导致第二个异常。同样,这可以通过与其他代码一起进行相同的注册来解决。那么AppBuilder.UseReactiveUI
扩展方法可以省略:
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();
Locator.CurrentMutable.RegisterConstant(new AvaloniaActivationForViewFetcher(), typeof(IActivationForViewFetcher));
Locator.CurrentMutable.RegisterConstant(new AutoDataTemplateBindingHook(), typeof(IPropertyBindingHook));
RxApp.MainThreadScheduler = AvaloniaScheduler.Instance;
var container = builder.Build();
resolver.SetLifetimeScope(container);
BuildAvaloniaApp().Start(AppMain, args);
扩展方法
现在,在类似于我们用来设置 Splat 和 ReactiveUI 的扩展方法中,这看起来会更好:
public static void InitializeAvalonia(this IMutableDependencyResolver resolver)
resolver.RegisterConstant(new AvaloniaActivationForViewFetcher(), typeof(IActivationForViewFetcher));
resolver.RegisterConstant(new AutoDataTemplateBindingHook(), typeof(IPropertyBindingHook));
RxApp.MainThreadScheduler = AvaloniaScheduler.Instance;
和
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();
Locator.CurrentMutable.InitializeAvalonia();
var container = builder.Build();
resolver.SetLifetimeScope(container);
BuildAvaloniaApp().Start(AppMain, args);
【讨论】:
以上是关于如何在 Avalonia.ReactiveUI 中使用 Autofac 作为 DI 容器?的主要内容,如果未能解决你的问题,请参考以下文章