Laden...

Zyan Communication Framework

Letzter Beitrag vor 8 Jahren 74 Posts 78.813 Views
Anonyme Typen

Hallo Heinz,

sorry, dass die Antwort erst so spät kommt, aber ich habe momentan sehr viel zu tun, was sich leider negativ auf meine Antwortzeiten auswirkt.

Woran kann es liegen, dass ich keinen anonymen Typparameter als Funktionsparameter benutzen kann?

Anonyme Typen werden von Zyan nicht unterstützt. Das liegt daran, dass sie zur Laufzeit erstellt werden und deshalb in einer entfernten Anwendungsdomäne nicht verfügbar sind.

Zyan erkennt die aufzurufende Methode an ihrer Signatur. Dabei sind Methodenname, Typ des Rückgabewerts und die Typen der Parameter relevant. Der Dispatcher (das ist die interne Komponente, welche Remoting-Nachrichten parst und sie in reale Methodenaufrufe auf dem Server verwandelt) überprüft dabei die Typ-Kompatiblität der übergebenen Parameterwerte mit der Methodensignatur. Er kann aber nur dann ermitteln, ob ein Typ mit einem anderen kompatibel ist, wenn er beide kennt.

Anonyme Typen, die zur Laufzeit auf dem Client erzeugt werden, kann der Server nicht kennen. Der Server versucht unbekannte Typen aus den entsprechenden Assemblies nachzuladen. Da anonyme Typen aber flüchtig sind und nicht als Assembly vorliegen, klappt das natürlich nicht. Zyan kann den Typ nicht laden und so auch nicht ermitteln, ob er mit dem entsprechenden Parameter aus der Signatur der aufzurufenden entfernten Methode kompatibel ist. Als Folge davon geht Zyan davon aus, dass für den Aufruf keine passende Überladung vorhanden ist.

So kommt der Fehler "Methode nicht gefunden" zustande.

Es ist theoretisch möglich auch anonyme Typen automatisch auf den Server zu bringen. Dazu müssten aber die Rohdaten des dynamischen Kompilats serialisiert und automatisch mit der Remoting-Nachricht mitgeschickt werden. Derzeit ist so ein Mechanismus nicht in Zyan vorhanden.

Ich sehe das auch kritisch wegen der Performance. Die Rohdaten des anonymen Typs müssten auf dem Server auch wieder in eine ladbare Form gebracht werden. Da würde sich dann die Frage stellen, ob man diese übertragenen anonymen Typen sinvoll cachen kann, also ob man erkennen kann, wann es sich um den selben anonymen Typ handelt.

Für entfernte Methodenaufrufe musst Du derzeit also leider noch auf anonyme Typen verzichten.

Es gibt aber schon ein erfasstes Feature im Zyan Issue Tracker: http://zyan.codeplex.com/workitem/626

Du bist nicht der Erste, der sich anonyme Typen für entfernte Methodenaufrufe wünscht.

Gruß
Rainbird

Hallo Rainbird,

kein Problem, dass die Antwort etwas gedauert hat. Zyan ist eine super Komponente und kostenlos. Da kann man es nicht auch noch verlangen, dass man so schnelle Antwortzeiten hat, wie bei einer Komponente, die richtig Geld kostet 😉

Schade dass es (noch) nicht funktioniert. Aber es beruhigt mich, dass die Anfrage auch von anderen gestellt wurde 🙂

Kannst du es abschätzen, wann es implementiert wird oder ist es nur auf der ToDo-Liste für eine spätere Version, die irgendwann kommt?

Gruß
..Heinz..

Echt eine super Komponente.... Funktioniert sehr zuverlässig!!!! Gratulation!

Danke

Hallo lmdf,

danke fürs positive Feedback. Freut mich, dass Dir meine Komponente nützlich ist.

Gruß

Rainbird

Hallo Rainbird,

ich würde Zyan gerne für ein privates Projekt verwenden. Allerdings müsste ich den Service an eine bestimmte IP-Adresse binden, damit sich die Clients ausschließlich über VPN verbinden können. Ist das irgendwie möglich?

Binden an bestimmte IP

Hallo felix,

das ist ganz einfach möglich. Allerdings wird das binden an eine bestimmte IP-Adresse nicht von allen Kanaltypen unterstützt.

Wenn Du keine Events oder Callbacks durch Client-Firewalls hindurch übertragen musst, kannst Du ein TcpCustomServerProtocolSetup wie folgt verwenden:

// TCP-Protokoll mit unverschlüsselter binärer Datenübetragung
var protocol = new TcpCustomServerProtocolSetup
                   (
                        8080, // TCP-Port
                        new BasicWindowsAuthProvider(), // Authentifizierung mit Windows-Benutzername und Passwort
                        true // Verschlüsselung eingeschaltet
                   );

// TCP-Kanal an bestimmte IP-Adresse binden
//TODO: Statt 192.168.0.10 die gewünschte eigene IP-Adresse einsetzen
protocol.ChannelSettings.Add("bindTo", "192.168.0.10");
protocol.ChannelSettings.Add("machineName", "192.168.0.10"); // Nur setzen, wenn Server eine öffentliche statische IP hat! Bei DynDNS etc. nicht setzen!
protocol.ChannelSettings.Add("useIpAddress", true); // Nur setzen, wenn Server eine öffentliche statische IP hat! Bei DynDNS etc. nicht setzen!

Über die ChannelSettings kann man direkt Einstellungen des Kommunikationskanals einstellen. Das TcpCustomServerProtocolSetup verwendet einen TcpChannel. Dessen Konfigurationseinstellungen kannst Du hier nachlesen: MSDN Libraray: Channel und Formatter Configuration
Gruß
Rainbird

Hallo Rainbird,

vielen Dank für deine Antwort. Ich werde das in den nächsten Tagen mal ausprobieren 😃

Hallo Rainbird,

dein Beispiel funktioniert einwandfrei. Danke nochmal.
Allerdings habe ich jetzt das Problem, dass der Server ein Event feuern muss, das alle angemeldeten Clients registrieren können. Ich habe bereits in RainBirds Zyan: Server Event am Client abrufen (oder Alternativen?) ein Beispiel von dir dazu gefunden. Allerdings ist ZyanComponentHost.StartNotificationService() als deprecated markiert.

Mein Event existiert. Es wird vom Server auch gefeuert, allerdnigs kommt es beim Client nicht an.

Hast du vielleicht ein Artikel zur Hand, in dem man nachlesen kann, wie das mit Remote Delegates funktioniert?
Ich habe mit .NET Remoting bisher leider noch nicht so viel gemacht.

Gruß,
Felix

Events mit Zyan

Hallo felix,

die einfachste Variante wären ganz herkömmlich Events. Wenn Du Zyan verwendest, kannst Du Events ganz intuitiv verwenden, genau so wie bei ein Click-Ereignis eines Buttons auf einem Windows-Formular.

In der Zyan-Doku gibt es dafür ein Beispiel: Ereignisse einsetzen

Solche verteilten Ereignisse verhalten sich dabei genauso wie herkömmliche lokale Ereignisse. Die Abonnenten des Ereignisses werden nacheinander aufgerufen. Das ist aber nicht immer das, was man erreichen will. Manchmal möchte man, dass der Server alle registrierten Clients möglichst gleichzeitig informiert. Dann kann man statt Events mit Delegaten arbeiten. Ein einfacher serverseitiger Benachrichtigungsdienst mit Delegaten könnte z.B. so aussehen:

public class SomeServerComponent : ISomeServerComponent
{
    private ConcurrentDictionary<Guid, Action<string>> _subscribers = new ConcurrentDictionary<Guid, Action<string>>();

    public Guid Subscribe(Action<string> clientCallback)
    {
        if (clientCallback == null)
            throw new ArgumentNullException("clientCallback");

        Guid subscriptionID = Guid.NewGuid();
        _subscribers.TryAdd(subscriptionID, clientCallback);
        return subscriptionID;
    }

    public void Unsubscribe(Guid subscriptionID)
    {
        Action<string> clientCallback;
        _subscribers.TryRemove(subscriptionID, out clientCallback);
    }

    public void NotifyClients(string message)
    {
        Parallel.ForEach(_subscribers.Values, callback => 
        {
            try
            {
                callback(message);
            }
            catch (SocketException)
            {
                //TODO: Ausnahme loggen
            }
            catch (RemotingException)
            {
                //TODO: Ausnahme loggen
            }
        });
    }
}

Der Client kann sich ganz einfach für Benachrichtigungen registrieren.

ISomeServerComponent proxy = _connection.CreateProxy<ISomeServerComponent>();
proxy.Subscribe(OnServerNotification);

Wenn auf dem Server NotifyClients aufgerufen wird, führt das dann dazu, dass auf dem Client OnServerComponent aufgerufen wird.

private void OnServerNotification(string message)
{
    Console.WriteLine(message); 
}

Hallo Rainbird,

vielen Dank für deine ausführliche Antwort. Ich gehe das heute abend nochmal ganz genau durch. Irgendetwas übersehe ich momentan noch. Falls es gar nicht klappt, baue ich mal eine Beispiel-Applikation mit der man das Verhalten nachvollziehen kann.

Gruß,
Felix

Hallo Rainbird,

ich habe gestern dein Beispiel ausprobiert. Es funktioniert alles wunderbar! Vielen Dank nochmal für deine Hilfe 😃

Den Service lasse ich auf meinem Linux Server unter Mono 2.10 laufen. Wenn ich den Service im Hintergrund laufen lassen möchte, geht das momentan nur mit screen, da der Service ansonsten sofort wieder gestoppt wird (auch wenn ich das &-Zeichen hinter den Befehl hänge). Aber das werde ich wohl auch noch irgendwie hinbekommen.

Gruß,
Felix

Windows-Dienst als Dämon unter Linux laufen lassen

Hallo felix,

mono liefert eine Runtime für Windows-Dienste unter Linux. Damit sollte es möglich sein, Deinen Server als Linux-Dämon im Hintergrund laufen zu lassen.

Schau mal: Mono Documentation: mono-service

Gruß
Rainbird

Hallo Rainbird,

das habe ich schon probiert. Es gibt sogar eine neue Version "mono-service2". Aber ich hatte immer einen der folgenden Fälle:

  1. Der Service wurde erwartungsgemäß in den Hintergrund verschoben, hat aber auf Client-Verbindungsanfragen nicht mehr reagiert.
  2. Der Service wurde beim Starten sofort wieder beendet.

Irgendwo in den untiefen des Mono-Forums habe ich dann gelesen, dass mono-service unter Debian nicht richtig funktioniert. ich glaube ich werde das demnächst nochmal in einer virtuellen Maschine durchtesten.

EDIT:
Ich habe mich jetzt nochmal genauer mit dem Thema Services unter Mono beschäftigt. Ich bin bisher davon ausgegangen, dass "mono-service2" die neuere Version von mono-service ist. mono-service2 ist aber einfach nur für .NET 2.0.

Wenn man aber einen Windows-Service damit hostet (d.h. wenn die Service-Klasse von System.ServiceProcess.ServiceBase erbt), dann funktioniert alles wunderbar. Ich hatte vorher versucht, eine normale Konsolen-Anwendung mit mono-service laufen zu lassen. Das funktioniet aber scheinbar nicht.

Gruß,
Felix

Zyan 2.4 veröffentlicht

Hallo Zusammen,

Zuerst möchte ich mich für die über 650 Downloads bei NuGet und über 3400 Downloads auf Codeplex seit der Veröffentlichung von Zyan bedanken.
Viele der Features, die Zyan inzwischen mitbringt, sind durch das rege Feedback der Community angeregt worden.
Ich hoffe, dass auch die neue Version 2.4 so regen Zuspruch findet.

Neben zahlreichen Bugfixes bietet Zyan 2.4 folgende neue Features:*Komprimierung des Datenverkehrs (besonders nützlich bei langsamen Intrnetverbindungen) *Verbesserungen beim Handling von verteilten Ereignissen

  • Ereignisse für Single-Call- und Singleton-Komponenten verwenden nun die selbe Semantik
  • Ereignisse werden serverseitig nun standardmäßig asynchron verarbeitet
  • Alte synchrone Ereignisverarbeitung kann bei Bedarf über ZyanComponentHost.LegacyBlockingEvents eingeschaltet werden
  • Registrierung und Deregistrierung von Ereignissen kann nun auch über Call-Interception abgefangen und im Verhalten dynamisch geändert werden

*Verbesserungen bei der Clientverbindung (ZyanConnection)

  • ZyanConnection.Reconnected-Ereignis benachrichtigt nun bei Verbindungswiederherstellung nach einem abgefangenen Abbruch der Socketverbindung
  • Das zu verwendende Client-Protokoll wird nun automatisch anhand des angegebenen Verbindungs-URLs erkannt

*Verbesserungen beim TCP-Duplex-Transportkanal

  • Unterstützt nun explizite Bindung an eine bestimmte Netzwerkkarte auf mehrfach vernetzten Computern (bindTo Kanaleinstellung; Analog zum Standard-TCP-Transportkanal)
  • Unterstützt nun Initiierung der Socketverbindung bei der Ersten Verbindung (einstellbar über ConnectDuringCreation Parameter)

*Neuer Null-Transportkanal für Test- und Monitoringzwecke *Verbesserte Kompatibilität zum Mono Framework

Eine Liste mit allen Neuerungen und Bugfixes findet ihr unter: http://zyan.codeplex.com/releases/view/84528.

Eine detaillierte Beschreibung der neuen Features steht auf folgender Seite: What´s new in Zyan 2.4?

Die Binaries könnt ihr hier runterladen: Zyan 2.4 Download

Zyan 2.4 kann auch bequem über NuGet gezogen werden: NuGet Gallery | Zyan 2.4

Liste mit Referenzen: Projects using Zyan Framework

Wenn ihr Bugs findet, meldet sie bitte im Issue Tracking System: Zyan Issue Tracking

Fragen, Anregungen und Diskussionen gerne hier auf mycsharp.de oder direkt im Zyan Diskussionsbereich

Gruß
Rainbird

Zyan 2.6 veröffentlicht

Hallo Zusammen,

Zyan 2.6 ist da!
Die neue Version bringt folgende Neuerungen mit:
*Unterstützung für Android (in Verbindung mit Xamarin Mono for Android!); Bereits ab Zyan 2.5 *Automatische Ermittlung laufender ZyanComponentHost-Instanzen im LAN (#2085)

  • Findet automatisch und asynchron laufende Zyan-Server im LAN
  • Findet Server anhand ihres Namens und/oder der Serverversion
  • Verwendet UDP broadcasts (Unabhängig von Adresse und Port des Zyan-Servers)
  • Discovery ist standardmäßig ausgeschaltet und muss bei Bedarf explizit aktiviert werden
  • Wird durch Aufrufen von "zyanHost.EnableDiscovery()" eingeschaltet
  • Clientseitig "ZyanConnection.DiscoverHosts(name, callback)" aufrufen, um lafende Server zu suchen

*Registrieren und Deregistrieren von Ereignishandlern erfolgt nun standardmäßig nebenläufig (#2308):

  • Altes Verhalten (blockiert den Thread, bis Ereignisregistrierung abgeschlossen ist) kann über "ZyanSettings.LegacyBlockingSubscriptions" wiederhergestellt werden

*Unterstützung für Synchronisierungskontext für Callbacks und Ereignisse (#1827):

  • Vereinfacht die Ereignisbehandlung in UI-Anwendungen (WPF, Windows.Forms)
  • Ist standardmäßig ausgeschaltet und muss bei Bedarf explizit aktiviert werden
  • Kann bei Proxyerstellung einzeln aktiviert werden
  • ZyanCatalog aktiviert Synchronisierungskontext-Unterstützung standardmäßig für alle Proxies, die er erzeugt

*Wiederverbinden von entfernten Ereignissen wird nun mittels schneller Stapelverarbeitung durchgeführt (statt durch Einzelaufrufe in einer Schleife) (#2309) *Neues Ereignis: ZyanComponentHost.ClientLogonCanceled (bei Anmeldungsabbruch) (#2318) *Neue Eigenschaft: AuthRequestMessage.ClientAddress (enthält die IP-Adresse des Clients) *Unterstützung für AuthorizedGroup und ExclusiveAddressUse Einstellungen für IPC Protokoll-Setups (#2345) *Unterstützung für .NET Framework v4.5/4.5.1 (#2295) *Neues Beispiel Projekt: Zyan Drench, ein Spiel für Android, 50K+ Downloads bei Google Play

Detaillierte Liste der behobenen Bugs: https://zyan.codeplex.com/releases/view/110163

Auf diesen Wegen könnt ihr die neue Version 2.6 ziehen:*Zyan Homepage *Zyan NuGet Paket *Zyan 2.6 Binary Download Seite *Zyan Source Code Seite *Zyan SVN Repository

Bugs könnt ihr wie immer auf CodePlex im Issue Tracker melden.

  • Neues Beispiel Projekt: Zyan Drench, ein Spiel für Android, 50K+ Downloads

Hi,

auch wenn das Spiel nur ein Nebenprdukt zu sein scheint: 👍
Was noch nett wäre bzgl. des Spiels: aktuell scheint es nur auf Telefonen zu laufen. Auf meinem Nexus 10 Tablet lässt sich das Spiel installieren und die App öffnen, aber nach einem Klick auf "Play against Android" schließt sich die App wieder.

Hallo,

ich möchte meine Anwendung auf Asynchron umstellen, zum testen versuche ich folgendes Beispiel:


public async Task<bool> SqlConnectionExistsAsync()
{
  try
  {
    return await zyanProxy.SqlConnectionExistsAsync();
  }
  catch (Exception ex)
  {
    System.Diagnostics.Debug.WriteLine("ex " + ex.Message);
  }
 }

public interface ILogonServiceAsync : ILogonService
    {
        Task<bool> SqlConnectionExistsAsync();
    }

//Zyan program.cs:
catalog1.RegisterComponent<ILogonServiceAsync, LogonService>();

 public async Task<bool> SqlConnectionExistsAsync()
        {
            string connString = ConfigurationManager.ConnectionStrings["ExampleConnection"].ConnectionString;

            using (SqlConnection connection = new SqlConnection(connString))
            {
                try
                {
                    await connection.OpenAsync();
                    return true;
                }
                catch (SqlException ex)
                {
                    return false;
                }
            }
        }

Die Verbindung kommt zustande, der user loggt ein.

Der Debugger steigt mir anschließend aus im Zyan ConnectionErrorEventHandler. mit : > Fehlermeldung:

Der Typ "System.Threading.Tasks.Task`1[[System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]" in Assembly "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" ist nicht als serialisierbar gekennzeichnet.

Habe versucht mir das hier abzugucken:
http://zyan.codeplex.com/discussions/347146

Was mache ich falsch? Wie könnte ich es richtig machen?

Danke.

Hast du denn das Zielframework auf mindestens Net 4.5 umgestellt?

Hast du denn das Zielframework auf mindestens Net 4.5 umgestellt?

Ja. Auf 4.5
Und die ZyanCommunication.dll 4.5 von 43825 (2.6?)

Die gleiche Methode Synchron, kommt kein Fehler.

Habe nun nochmal die Asynchrone getestet, die Methode wird korrekt ausgeführt, liefert im beispiel oben True/false je nachdem ob SQL Server vorhanden, aber eben "Ist als nicht serialisierbar" gekennzeichnet. Hmm...

Hi,

Alex(yallie) war so freundlich

falls mal noch jemand das braucht:
👍

Hi Peter,

Use async methods on the client side only.  
Don&#39;t use Task types in your interfaces, they are not serializable anyway.  
Whenever you call a server method, wrap the call with Task.Run().  

Just as simple as that.

Here is an example:

  
// note that server component interface is synchronous  
public interface ISampleService  
{  
    string GeneratePassword(int length);  
}  
  
// and client code is asynchronous  
using (var conn = await Task.Run(() => new ZyanConnection(url, protocol)))  
{  
    var proxy = conn.CreateProxy<ISampleService>();  
  
    var password = await Task.Run(() => proxy.GeneratePassword(length));  
    Console.WriteLine("Server generated password: {0}", password);  
}  
  

The complete code for this example is located here:

>

Regards, Alex

Hallo Leute,
ich bin neu hier im Forum und hab sofort eine Frage zum Zyan Framework. Kann ich das hier stellen? Sonst können die Mods mir gerne Bescheid geben und ich verschiebe meine Frage an die entsprechende Stelle.

Meine Frage ist, ob ich an einem Zyan-Client erstelltes Objekt (mit der connection.CreateProxy-Methode) einer Methode eines anderen Objektes übergeben kann?
Beispiel:


var hTasse = connection.CreateProxy<ITasse>();
var hSchrank = connection.CreateProxy<ISchrank>();

hSchrank.StelleRein(hTasse);

Bei mir passiert es beim Methodenaufruf, dass ich eine "MissingMethodException" bekomme, weil der die Mehtode Schrank.InitializeLifetimeService() nicht findet. Diese Methode kommt aus dem Zyan-Framework, die hab ich nicht programmiert.

Kann mir da einer weiterhelfen?

Gibt es sonst irgendwo eine Dokumentation mit Code-Beispielen von Zyan? Ist schon eine mega super Sache, aber leider bringen mir die reinen Methodennamen und Klassen aus der API nicht so viel Infos, dass ich das ohne weitere Erklärung verstehe.

Danke schonmal!!!

Hallo nickname8,

Dokumentation zu Zyan findest Du hier: Zyan Dokumentation (deutsch)

Code-Beispiele findest Du hier: Codeplex: Zyan Code-Beispiele (Examples)

Nun zu Deinem Probelm. Sowohl Tasse als auch Schrank sind auf einem Zyan-Server veröffentlichte Remote-Komponenten. Du versuchst, einen clientseitigen Verweis auf die entfernte Komponente Tasse an die entfernte Komponente Schrank zu übergeben. Das wird so nicht unterstützt.

Zyan trennt strikt zwischen Client und Server. Der Server bietet Funktionalität an, der Client konsumiert sie. Wenn Client und Server Daten austauschen, dann muss dies über Typen gemacht werden, die serialisierbar sind (Also alle Typen, die ISerializable implementieren oder mit [Serializable] gekennzeichnet sind, und primitive Typen wie int, string, byte, etc.)

Es gibt deshalb grundsätzlich zwei Kategorien von Klassen:*Komponenten, die Funktionalität anbieten *Datenklassen, welche zum verseden von Daten übers Netzwerk eingesetzt werden

Damit Dein Beispiel funktioniert, müsste Tasse eine serialisierbare Datenklasse sein und NICHT als Remote-Komponente am Zyan-Server veröffentlicht werden. Es könnte z.B. eine Komponente "TassenFabrik" geben, welche Tassen produziert und die fertigen Tassen als Datenklassen zurückgibt. Die kann man dann mit proxySchrank.StelleRein(datenTasse) auch an den entfernten Schrank schicken.

Hi,
super, vielen Dank! Das hilft mir schonmal sehr weiter! Werde meine Software entsprechend designen.
Jetzt hab ich noch eine andere Frage: Ich möchte die Klassen ebenfalls in eine PCL schreiben, damit sowohl Client als auch Server damit umgehen kann. Die CL muss portable sein, damit ich das auch in entsprechenden Xamarin-Projekten nutzen kann. Jetzt ast du geschrieben, dass die Datenklassen serialisierbar sein müssen. [Serializable] ist aber nicht verfügbar für PCLs. Dafür kann ich andere 3rd party PCLs nutzen. Kann/Muss ich Zyan irgendwie sagen, wie der (de)serialiseren soll?
Ich möchte zum Beispiel Newtonsoft Json.net zum serialisieren nutzen. Wenn ich jedoch die entsprechenden Attribute in die zu serialisierbaren Klassen schreiben, bekomme ich trotzdem eine SerializationException.
LG