2017-03-07 6 views
1

Um zu beginnen, lassen Sie mich sagen, dass ich hier einige Fragen über SingleInstance gelesen habe, aber immer noch keine direkte Antwort finden kann, die mir hilft. Das heißt, ich entschuldige mich, wenn ich etwas verpasst habe.Autofac SingleInstance() und Xamarin Forms

Hier ist meine Frage:

Ich baue eine Xamarin Forms-App für iOS und Android. Ich habe eine einzelne AppInitializer-Klasse in einer PCL, in der ich alle meine Schnittstellenabhängigkeiten mit Autofac registriere. Ich weise den Container dann dem Builder als statische Eigenschaft für die App-Klasse zu. Das Problem, auf das ich stoße, ist, dass ich, während ich alles mit .SingleInstance() registriere, keine einzige Instanz bekomme.

Init Logic Beispiel:

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

Ich lasse Autofac in meinem Konstrukteurs Lösung Schnittstellen handhaben. Zum Beispiel:

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

ich sagte dann verwenden Sie das Modell auf einer Seite wie folgt:

Beispielseite Nutzung:

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

In diesem Beispiel habe ich Model.CurrentMember die Eigenschaften sofort eingestellt vor der Ankunft auf dieser Seite. Ich habe Breakpoints gesetzt und weiß genau, dass das passiert. Wenn ich jedoch die Instanz des Modells auflösen, sind die Eigenschaften von CurrentMember null.

Mache ich hier etwas falsch oder habe ich einen Fehler gefunden?

-Edit- Es wurde klar, dass ich Autofac verwende.

-Edit 2- Hinzufügen weiterer Details.

Meine Implementierung der IMemberViewModel-Klasse weist verschiedene Eigenschaften auf, darunter ein beobachtbares Objekt namens current member. Es wird, wie unten erklärt:

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

über die Durchführung der IMemberViewModel Ich habe eine Methode, die die verschiedenen Eigenschaften auf Currentmember setzt.

Die Reihenfolge der Operationen ist dies:

Der Endbenutzer tippt ein Bild für ein Mitglied. Dies löst einen Befehl für die (theoretisch) Singleton-Instanz der IMemberViewModel-Implementierung aus. Dieser Befehl führt eine asynchrone Task aus, die auf einen asynchronen Aufruf an die API wartet, um die Daten für dieses Member zu laden. Nachdem die Daten geladen und die Eigenschaften in CurrentMember festgelegt wurden, navigiert die App zum Profilbildschirm. Der Profilbildschirm löst IMemberViewModel auf (siehe oben).

erwartetes Verhalten: Die Eigenschaften auf Currentmember aus der aufgelösten Instanz IMemberViewModel auf die Werte gesetzt, die gerade von der Lastdaten Verfahren eingestellt wurden. Diese Erwartung ergibt sich aus der Annahme, dass es eine einzelne Instanz von IMemberViewModel gibt.

tatsächliches Verhalten: Die Currentmember Eigenschaften der Standardwerte sind, das heißt string.Empty, 0, null usw.

Das Seltsame dabei ist, dass dies nicht zu jedem Modell geschieht. Ich habe ein Nachrichtenmodell, das ich auf die gleiche Weise auf dem gleichen Bildschirm auflösende und es scheint in Ordnung zu sein.

+1

, wenn Sie sagen, Sie setzen 'Model.CurrentMember' Eigenschaften vor auf der Seite ankommen, haben Sie meinen Sie gelöst' IMemberViewModel' aus demselben Behälter und die Eigenschaften festgelegt? –

+0

Das CurrentMember des Modells ist ein beobachtbares Objekt mit einigen String-Eigenschaften. Ich setze diese Zeichenfolgen (wie Name) direkt aus einem Ladedatenaufruf in der Implementierung von IMemberViewModel. Meine Erwartung ist, dass wenn ich das IMemberViewModel auflöse, ich die einzelne Instanz der Implementierung bekomme. Stattdessen erhalte ich eine neue Instanz dieser Implementierung. Ich werde meine Frage mit mehr Details aktualisieren. – Kerfuffle

+0

@ MickaëlDerriey. Ich habe vergessen, dich in meiner Antwort zu markieren. – Kerfuffle

Antwort

0

Dieses Problem wurde durch die Art verursacht, wie wir alles initialisieren wollten. Für die Nachwelt werde ich kurz erzählen, was geschah und was ich getan habe, um es zu verhindern.

Zurück App Fluss:

  • App öffnet & Konstruktor aufgerufen wird. Dies ruft die obige Initialisierungsroutine auf.
  • Benutzer meldet sich an.
  • Die erste Instanz von IMemberViewModel wurde mithilfe des statischen Containers aufgelöst.
  • Eine Nachricht, die den Benutzer für Push Notifications Berechtigungen fragen erscheint
  • Wenn dies geschieht, wird die App OnSleep genannt (iOS)
  • Nachdem der Benutzer eine Antwort auswählt, wird onResume genannt.
  • OnResume ruft Initialisierungsroutine auf
  • Neuer Container erstellt.
  • Aufruf zum Laden von Daten geschieht auf alten Container, neue Seiten verweisen auf neue Container.
  • Problem entsteht wie oben beschrieben.

Korrektur zur Strömung:

Zuerst von dem, was ich den init Anrufe müssen nicht auf Wiederaufnahme gemacht werden kann sagen, und/oder gestartet werden, wenn in dem App-Konstruktor gemacht. Wenn die App "gelöscht" wird, weil andere Apps Speicherplatz benötigen, wird beim nächsten Start eine neue Version der App erstellt (siehe Android Activity Lifecycle und iOS App Lifecycle).

Zweitens, weil ich paranoid bin und es nicht schaden kann, überprüfe ich jetzt in der App-Init-Routine, ob der Container existiert und ob die Schnittstelle bereits registriert ist.

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

    RegisterDependencies(setup); 
    … 
} 

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