Autofac SingleInstance()和Xamarin表单

时间:2017-03-07 16:19:52

标签: xamarin.forms autofac single-instance

首先,请允许我说我在这里读过几个关于SingleInstance的问题,但仍然无法找到有助于我的直接答案。也就是说,如果我错过任何事情,我会道歉。

这是我的问题:

我正在为iOS和Android构建一个Xamarin Forms应用程序。我在PCL中有一个AppInitializer类,我使用Autofac注册所有的接口依赖项。然后,我将构建器中的Container分配为app类的静态属性。我遇到的问题是,当我使用.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。

-Edit 2 - 添加更多细节。

我对IMemberViewModel类的实现有各种属性,包括一个名为current member的可观察对象。它声明如下:

 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属性设置为刚从load数据方法设置的值。这种期望源于假设有一个IMemberViewModel实例。

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

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

1 个答案:

答案 0 :(得分:0)

这个问题原因是我们开始初始化所有内容的方式。为了后人的缘故,我将简要介绍一下发生了什么以及我采取了哪些措施来阻止它。

上一个应用流程:

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

对流程进行更正

首先,我可以告诉我,如果在app构造函数中创建,则不需要在resume和/或start上进行init调用。如果应用被“杀死”,因为其他应用需要内存空间,则会在下次发布时创建应用的新版本(请参阅Android Activity LifecycleiOS App Lifecycle)。

其次,因为我是偏执狂,因为它不会受到伤害,所以在app init例程中我现在正在检查以确定容器是否存在以及接口是否已经注册。

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

    RegisterDependencies(setup);
    …
}

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