【问题标题】:Autofac SingleInstance() and Xamarin FormsAutofac SingleInstance() 和 Xamarin 表单
【发布时间】:2017-03-07 16:19:52
【问题描述】:

首先,让我说我在这里阅读了几个关于 SingleInstance 的问题,但仍然找不到对我有帮助的直接答案。也就是说,如果我遗漏了什么,我深表歉意。

这是我的问题:

我正在为 iOS 和 Android 构建一个 Xamarin Forms 应用程序。我在 PCL 中有一个 AppInitializer 类,我在其中使用 Autofac 注册所有接口依赖项。然后,我将构建器中的 Container 分配为应用程序类的静态属性。我遇到的问题是,当我使用 .SingleInstance() 注册所有内容时,我实际上并没有获得单个实例。

初始化逻辑示例:

var builder = new ContainerBuilder();
builder.RegisterType<ErrorHandler>().SingleInstance().As<IErrorHandler>();
…
builder.RegisterType<MemberViewModel>().SingleInstance().As<IMemberViewModel>();
…
AppContainer.Current = builder.Build();

我让 Autofac 处理我的构造函数中的接口解析。例如:

public MemberViewModel(ISettingsViewModel settings, IErrorHandler errorHandler, …) : base(settings, errorHandler){…}

然后我在如下页面上使用该模型:

页面使用示例:

public ProfilePage()
{
     InitializeComponent();
     var displayModel = Model.CurrentMember;
     …
 }
 …
 **public IMemberViewModel Model =>
 AppContainer.Current.Resolve<IMemberViewModel>();**

在此示例中,我在到达此页面之前立即设置了 Model.CurrentMember 的属性。我已经设置了断点,并且知道这是正在发生的事实。但是,当我解析模型实例时,CurrentMember 上的属性为空。

我在这里做错了什么还是遇到了错误?

-编辑- 明确表示我正在使用 Autofac。

-编辑 2- 添加更多细节。

IMemberViewModel 类的实现具有各种属性,包括一个称为当前成员的可观察对象。声明如下:

 public class MemberViewModel : ViewModelBase, IMemberViewModel
 {
  … 
  (see constructor above)
  …
  public MemberDisplay CurrentMember =>
        m_CurrentMember ?? (m_CurrentMember = new MemberDisplay())

关于 IMemberViewModel 的实现,我有一个方法可以设置 CurrentMember 的各种属性。

操作顺序是这样的:

最终用户点击成员的图像。这会在 IMemberViewModel 实现的(理论上)单例实例上触发命令。此命令执行异步任务,等待对 API 的异步调用以加载该成员的数据。加载该数据并在 CurrentMember 上设置属性后,应用程序将导航到配置文件屏幕。配置文件屏幕解析 IMemberViewModel(如上所述)。

预期行为: 已解析的 IMemberViewModel 实例中的 CurrentMember 上的属性设置为刚刚从加载数据方法设置的值。这种期望源于假设存在一个 IMemberViewModel 实例。

实际行为: CurrentMember 的属性为其默认值,即 string.Empty、0、null 等。

这里的奇怪之处在于,并非每个模型都会发生这种情况。我有一个消息模型,我正在同一个屏幕上以相同的方式解析它,它似乎很好。

【问题讨论】:

  • 当你说你在到达页面之前设置了Model.CurrentMember的属性,你的意思是你从同一个容器中解析了IMemberViewModel并设置了属性?
  • 模型上的 CurrentMember 是一个带有一些字符串属性的可观察对象。我在 IMemberViewModel 的实现中直接从加载数据调用中设置这些字符串(例如名称)。我的期望是,当我解决 IMemberViewModel 时,我得到了实现的单个实例。相反,我得到了该实现的一个新实例。我会更详细地更新我的问题。
  • @MickaëlDerriey。我忘记在回复中标记你了。
  • 所有你使用IMemberViewModel的地方,你确定你是从容器中解决的吗?老实说,我怀疑 Autofac 中是否存在错误。能否在构造函数和MemberViewModel 以及CurrentMember 属性的主体中都设置断点,调试并报告它们每个被命中的次数?
  • 我不能肯定地说,因为我不知道 Autofac 本身是如何解析接口的。我假设它使用我注册所有内容的容器,因为这是有道理的。我可以说我对接口的所有使用要么在类的构造函数中,要么通过同一个容器解决。

标签: xamarin.forms autofac single-instance


【解决方案1】:

这个问题原来是由我们初始化所有内容的方式引起的。为了后代着想,我将简要介绍正在发生的事情以及我为防止它所做的工作。

以前的应用流程:

  • 应用程序打开并调用构造函数。这会调用上面的初始化例程。
  • 用户登录。
  • IMemberViewModel 的第一个实例使用静态容器解析。
  • 会弹出一条消息,询问用户推送通知权限
  • 发生这种情况时,将调用应用 OnSleep (iOS)
  • 用户选择答案后,将调用 OnResume。
  • OnResume 调用初始化例程
  • 容器已创建。
  • 在旧容器上调用加载数据,新页面引用新容器。
  • 如上所述出现问题。

更正流程:

首先,据我所知,如果在应用程序构造函数中进行,则不需要在恢复和/或启动时进行初始化调用。如果应用程序因为其他应用程序需要内存空间而被“杀死”,则将在下次启动时创建应用程序的新版本(请参阅Android Activity LifecycleiOS App Lifecycle)。

第二,因为我是偏执狂,因为它不会受到伤害,所以我现在在应用程序初始化例程中检查以确定容器是否存在以及接口是否已经注册。

public static void Init(ISetup setup)
{
    if (Container != null && IsModelRegistered()) return;

    RegisterDependencies(setup);
    …
}

private static bool IsModelRegistered()
{
    return Container.IsRegistered<IMemberViewModel>();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-13
    • 2018-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多