[de] Frage zu Events (solved)

Topics: Technical Support
Jun 7, 2011 at 8:06 PM

Hallo zusammen,

erstmal großes Lob an die Entwickler von Zyan.

Ich bin noch neu im entwickeln von verteilten Anwendungen und bin gerade auf ein Problem gestoßen, bei dem ich nicht genau weiß, wie ich es lösen soll.

Folgendes Szenario: Ich habe eine "Server"-Anwendung (hier ein Windows Dienst, der Datensicherungen durchführt). Dort läuft ein Scheduler, der von außen gesteuert werden kann und manuell Sicherungen anstoßen kann. Dazu gibt es im Server eine Singleton Klasse für die zentrale Verwaltung, auf die die Remote Klasse zugreifen kann. Im "Client" (einfach die Hauptanwendung) soll es möglich sein, den Server zu steuern und Informationen live (den Status der Datensicherung) anzuzeigen. Das Steuern des Servers bereitet mir keine Probleme, aber die Nutzung von Events für die Aktualisierung der GUI in der Hauptanwendung.

Es gibt eine Klasse (nennen wir sie Status) für die Bereitstellung des aktuellen Statuses zuständig ist. Diese enthält ein Event das gefeuert wird, wenn sich etwas geändert hat. Jetzt würde ich gerade gerade dieses Event abgreifen, sodass im Clienten entsprechend die GUI aktualisiert wird.

Bereits ausprobiert: 

  1. Eine Klasse (Interface implementiert) im Clienten registriert sich auf dem Server. Sobald sich etwas ändert wird die Methode in der Klasse aufgerufen (sprich Observer Pattern). Dies habe ich leider nicht zum laufen bekommen.
  2. Der Server verbindet sich mit sich selbst, um ein remote freigegebenes Event zu feuern. Das hat relativ gut funktioniert, war aus meiner Sicht etwas umständlich; hat aber funktioniert.

Meine Frage ist nun, wie ich da am besten vorgehe, ohne alle Klassen zu serialisieren, die damit zusammenhängen. Wie kann ich also elegant das Ereignis remote verfügbar machen oder ist schon eins meiner Versuche zielführend?

Danke für Eure Hilfe.

Viele Grüße

Alex

Coordinator
Jun 7, 2011 at 11:25 PM
Edited Jun 7, 2011 at 11:37 PM

Hallo Alex,

danke für Dein Interesse am Zyan Framework. Deine Anforderungen sollten sich ohne große Probleme mit Zyan umsetzen lassen.

Bei Deinem Status-Ereignis soll der Server ja den Zustand einer bestimmten laufenden Sicherungsoperation an den Client senden. Angenommen Dein Client ist eine Windows.Forms-Anwendung. Die Klasse, welche sich für den Empfang des Status-Ereignisses interessiert, könnte dann z.B. ein Formular sein, welches vielleicht eine Fortschrittsanzeige aktualisieren soll, sobald sich der Status ändert. Wenn sich dieses Form-Objekt nun beim Server für den Ereignisempfang registrieren soll, muss der Server die Assembly des Client-Formulars zur Verfügung haben. Das hat er natürlich nicht, da ein Server in den allermeisten nicht abhängig von einem bestimmten Client sein sollte. Du könntest die Assembly natürlich auf den Server kopieren. Aber morgen erstellst Du einen zweiten Client mit ASP.NET, da man den Sicherungsserver auch übers Web fernstuern und überwachen kennen soll. Spätestens dann fällst Du dann auf die Nase, da der Server als Registrierung nur ein bestimmtes Windows.Forms-Formular akzeptiert.

Sowohl Client als auch Server können nur mit Typen arbeiten, die ihnen jeweils bekannt sind. Typen, welche Bestandteil des .NET Frameworks sind, kennen Server sowie Client grundsätzlich, da das .NET Framework ja auf beiden Computern installiert ist. Die Typen in Deinen selbsterstellten Assemblies sind nicht automatisch auf beiden Computern vorhanden. Da man die Server-Assemblies aber meistens nicht auf den Clients mitinstallieren will (und umgekehrt), erstellt man stattdessen eine separate Assembly, in welche alle Typen gepackt werden, die Client und Server gleichermaßen benötigen (vgl. http://zyan.codeplex.com/wikipage?title=Erste%20Schritte&referringTitle=Deutsche%20Dokumentation). Diese nenne ich z.B. genre Shared Assembly.

Um das Problem zu lösen, erstellst Du eine neutrale serialisierbare Klasse, welche die Werte einer Statusänderung beschreibt und packst diese Klasse in die gemeinsame "Shared" Assembly. Die Klasse könnte z.B. BackupOperationState heißen.

Hier ein konkreter Lösungsvorschlag:

// ---------------------- SHARED----------------------------

[Serializable]
public class BackupOperationState 
{
     public string BackupTaskName { get; set; }
     public string StatusMessage { get; set; }
     public int TotalFileCount { get; set; }
     public int CompletedFileCount { get; set; } 
}

public interface IBackupStateNotifier
{
    event Action<BackupOperationState> BackupOperationStateChanged;
}

// ---------------------- SERVER---------------------------- 

public class BackupStateNotifier : IBackupStateNotifier
{
    public event Action<BackupOperationState> BackupOperationStateChanged;

    internal void OnBackupOperationStateChanged(BackupOperationState state)
    {
        if (BackupOperationStateChanged != null)
        {
            try
            {
                BackupOperationStateChanged(state);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }  
}

// ---------------------- CLIENT ----------------------------

public partial class ClientForm
{
    private IBackupStateNotifier _proxy;

    public ClientForm(ZyanConnection connection)
    {
        _progressBar.Minimum=0;
        _progressBar.Value=0;
        _progressBar.Maximum=100;

        _proxy = connection.CreateProxy<IBackupStateNotifier>();
        _proxy.BackupOperationStateChanged += new Action<BackupOperationState>(UpdateProgressBar);    
    }

    private void UpdateProgressBar(BackupOperationState state)
    {
        if (InvokeRequired)
        {
            Invoke(new Action<BackupOperationState>(UpdateProgressBar), state);
            return;
        }
        int percent = Math.Round(Convert.ToDecimal(state.CompletedFileCount / state.TotalFileCount) * 100, 0);

        _progressBar.Value = percent;
        _messageLabel.Text = state.StatusMessage;
    }
}


Jun 8, 2011 at 2:41 PM

Vielen vielen Dank für die ausführliche Hilfe, das war genau das, nach dem ich gesucht habe. Mir hat einfach der letzte Denkanstoß gefehlt.

Viele Grüße

Alex