Autofac SingleInstance() и формы Xamarin

Для начала позвольте мне сказать, что я прочитал здесь несколько вопросов об SingleInstance, но все еще не могу найти прямой ответ, который мне помогает. Тем не менее, я прошу прощения, если я что-то пропустил.

Вот мой вопрос:

Я создаю приложение Xamarin Forms для iOS и Android. У меня есть один класс AppInitializer в PCL, где я регистрирую все свои зависимости интерфейса, используя Autofac. Затем я назначаю Контейнер из компоновщика как статическое свойство класса приложения. Проблема, с которой я сталкиваюсь, заключается в том, что, хотя я регистрирую все с помощью.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 равны нулю.

Я что-то здесь не так делаю или я столкнулся с ошибкой?

-Edit- дал понять, что я использую 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 (согласно выше).

Ожидаемое поведение: свойства CurrentMember из разрешенного экземпляра IMemberViewModel устанавливаются в значения, которые были только что установлены из метода загрузки данных. Это ожидание возникает из предположения, что существует единственный экземпляр IMemberViewModel.

Фактическое поведение: свойства CurrentMember имеют свои значения по умолчанию, то есть string.Empty, 0, null и т. Д.

Странно то, что это происходит не с каждой моделью. У меня есть модель сообщения, которую я решаю таким же образом на том же экране, и, кажется, все в порядке.

1 ответ

Решение

Эта проблема оказалась вызвана тем, как мы собирались все инициализировать. Ради потомков я кратко расскажу о том, что происходило и что я сделал, чтобы предотвратить это.

Предыдущий поток приложений:

  • Приложение открывается и конструктор называется. Это вызывает процедуру инициализации выше.
  • Пользователь входит в систему.
  • Первый экземпляр IMemberViewModel разрешен с использованием статического контейнера.
  • Появляется сообщение, запрашивающее у пользователя разрешения на push-уведомления.
  • Когда это происходит, вызывается приложение OnSleep (iOS)
  • После того, как пользователь выбирает ответ, вызывается OnResume.
  • OnResume вызывает процедуру инициализации
  • Новый контейнер создан.
  • Вызов для загрузки данных происходит в старом контейнере, новые страницы ссылаются на новый контейнер.
  • Проблема возникает как описано выше.

Исправление к потоку:

Во-первых, из того, что я могу сказать, не нужно делать вызовы init при возобновлении и / или запуске, если они сделаны в конструкторе приложения. Если приложение "убито" из-за того, что другим приложениям требуется пространство памяти, при следующем запуске будет создана новая версия приложения (см. Жизненный цикл активности Android и Жизненный цикл приложения iOS).

Во-вторых, из-за того, что я параноик и потому что это не может повредить, в процедуре инициализации приложения я сейчас проверяю, существует ли контейнер и зарегистрирован ли интерфейс.

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

    RegisterDependencies(setup);
    …
}

private static bool IsModelRegistered()
{
    return Container.IsRegistered<IMemberViewModel>();
}
Другие вопросы по тегам