如何使用 Xamarin 和 Autofac 将构造函数依赖项注入 ViewModel?
Posted
技术标签:
【中文标题】如何使用 Xamarin 和 Autofac 将构造函数依赖项注入 ViewModel?【英文标题】:How do I inject a constructor dependency into a ViewModel using Xamarin and Autofac? 【发布时间】:2018-04-27 12:27:15 【问题描述】:我有一个 ViewModel,我想向其中注入另一个类。我正在将 Visual Studio 与最新版本的 Xamarin 一起使用。我正在使用 Autofac 注册和解析依赖项。但我是新手,我遇到了一个我找不到解决方案的问题,即使它可能很简单。
这是我要注入另一个类的类:
public IMessagingCenterWrapper MessagingCenterWrapper;
public LoginViewModel(IMessagingCenterWrapper messagingCenterWrapper)
MessagingCenterWrapper = messagingCenterWrapper;
然后在应用程序的入口点,我有一个函数来初始化容器,该容器注册并解决依赖关系
static IContainer container get; set;
public App ()
InitializeComponent();
InitializeIOCContainer();
void InitializeIOCContainer()
var builder = new ContainerBuilder();
builder.RegisterType<LoginViewModel>();
builder.RegisterType<MessagingCenterWrapper>().As<IMessagingCenterWrapper>();
container = builder.Build();
var wrapper = container.Resolve<IMessagingCenterWrapper>();
var viewModel = container.Resolve<LoginViewModel>();
但是在登录视图中的行构建时出现错误:
BindingContext = new LoginViewModel();
我收到错误是因为我没有在调用中初始化参数。
但如果我这样做,我不会破坏 IoC 模式的整个原则。最终新的类调用将与其他依赖项嵌套,我想避免这种情况。
所以我的问题是:我如何在构造函数中实际注入类参数?
【问题讨论】:
在执行BindingContext = new LoginViewModel();
时,您根本没有使用 DI 容器。
@Fildor 你能解释一下它是如何完成的吗?因为容器是App入口点类的私有变量,在View中调用BindingContext = new LoginViewModel();
。
我承认我不知道 Autofac 的最佳实践。但我看到容器在 App 中是静态的。因此,您可以添加一个静态属性来解析 getter 中的实例。
调用Resolve<T>
不是反模式。你误会了。您需要调用Resolve<T>
才能让Autofac 为您创建对象。他们试图告诉你的是,从任何地方调用Resolve<T>
,但 Composition Root 是 一种反模式。为了能够解析根对象,您将必须调用Resolve<T>
。没有办法解决这个问题。
在 WPF 中可以做的是解析视图,然后调用 view.Show();。视图会将 LoginViewModel 作为构造函数中的参数,然后在第一行中将 DataContext 设置为 LoginViewModel 参数。
【参考方案1】:
这实际上是一个服务定位器注入,因为注入的元素是一个消息中心服务。这是个好消息。
您不必传入服务构造函数来查看模型构造函数。只需在您需要的地方请求服务:
public LoginViewModel()
MessagingCenterWrapper = App.Container.Resolve<IMessagingCenterWrapper>();
除非视图模型确实是全局的,否则不要将视图模型粘贴到 AutoFac 中。这种假国际奥委会有很多问题。
为了整体上更容易,这样怎么样:
// MUST BE PUBLIC
public static IContainer Container get; set;
static App()
InitializeIOCContainer();
public App ()
InitializeComponent();
private static void InitializeIOCContainer()
var builder = new ContainerBuilder();
builder.RegisterType<MessagingCenterWrapper>().As<IMessagingCenterWrapper>();
Container = builder.Build();
// Don't stick view models in the container unless you need them globally, which is almost never true !!!
// Don't Resolve the service variable until you need it !!!!
这些备注的完整代码位于https://github.com/marcusts/xamarin-forms-annoyances。请参阅名为 AwaitAsyncAntipattern.sln 的解决方案。
GitHub 站点还提供了有关此主题的更详细讨论的链接。
【讨论】:
服务定位器是一种既定的反模式。以上是关于如何使用 Xamarin 和 Autofac 将构造函数依赖项注入 ViewModel?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Avalonia.ReactiveUI 中使用 Autofac 作为 DI 容器?
如何使用 Autofac 注入相同的 DbContext 实例来处理 HTTP 请求而不会导致并发问题?