momentan wird eine TargetInvocationException geworfen, wenn Du das tust. Das liegt daran dass der Server die Client-Implementierung nicht kennt und den clientseitigen Delegaten deshalb nicht aufrufen kann.
Das Problem ist aber lösbar. Ich muss dem ZyanProxy nur beibringen, Delegaten-Parameter zu erkennen und eine Abfangvorrichtung davorzuhängen und zu verdrahten. Ich denke dass ist nützlich, da es Zyan noch intuitiver machen würde. Deshalb werde ich das in einer zukünftigen Version einbauen. Kann aber etwas dauern, bis ich dazukomme es einzubauen.
Danke für den Hinweis.
Dann habe ich nun folgende Punkte auf meiner Hausaufgabenliste:
Hosting von Anonymen Typen und generell Typen ohne Schnittstelle möglich machen
Sehr schön. Was mir auch noch nicht so gefällt ist das IChannel interface. Das ist ja ganz nett, weil es halt schon existiert, aber total überladen, da grauts einem echt davor , dass zu implementieren.
Für mich wäre MSMQ interessant, aber dsa IChannel zu implementieren macht ja gar kein Spaß...
Was mir auch noch nicht so gefällt ist das IChannel interface. Das ist ja ganz nett, weil es halt schon existiert, aber total überladen, da grauts einem echt davor , dass zu implementieren.
Die IChannel-Schnittstelle hat doch nur die folgenden drei Member:
string Parse(string,string)
string ChannelName {get;}
int ChannelPriority {get;}
Da ist doch nichts überladen. Aber eigentlich müsstest Du zusätzlich zu IChannel noch IChannelReceiver und IChannelSender implementieren, um einen vollständigen eigenen Transportkanal zu schreiben. Aber auch die sind alle nicht überladen. Schau:
Von Überladenen Schnittstellen kann also nicht die Rede sein. Man muss sich allerdings intensiv in die Architektur von Remoting einarbeiten. Ich will nicht behaupten, dass es eine triviale Aufgabe ist, einen eigenen Remoting-Transportkanal zu schreiben. Es ist aber nicht schwieriger, als einen eigenen Transport für WCF zu schreiben (eher sogar einfacher). Man bewegt sich immer auf der Ebene von Sockets, und Byte-Streams, wenn man einen eigenen Transportkanal schreibt. Das bringt einfach eine gewisse Komplexität und Systemnähe mit sich.
Da Zyan aber in Sachen Transportkanäle die Infrastruktur von .NET Remoting verwendet, lassen sich Remoting-Kanäle von Drittanbietern ganz eimfach einbinden. Einfach IClientProtocolSetup und IServerProtocolSetup implementieren und die Kanalerzeugung darin kapseln (Methode CreateChannel).
Zitat von malignate
Für mich wäre MSMQ interessant, aber dsa IChannel zu implementieren macht ja gar kein Spaß...
Es gibt bereits fertige MSMQ-Implementierungen für Remoting (und damit auch für Zyan). Diese hier z.B.: http://www.codeproject.com/KB/IP/msmqchannelnew.aspx http://www.codeproject.com/KB/IP/msmqchannel.aspx
Dieser MSMQ Remoting Kanal unterstützt das CallContext-Feature von Remoting und sollte deshalb auch grundsätzlich mit Zyan funktionieren. Da MSMQ vom Design her grundsätzlich asynchron arbeitet, werden aber vermutlich nicht alle Zyan-Features korrekt arbeiten, da MSMQ keine Rückgabewerte zurücksendet. Alle Aufrufe verhalten sich vermutlich dann wie OneWay-Aufrufe.
Du musst Dir also nicht die Arbeit machen, und einen eigenen MSMQ-Kanal schreiben. Wenn Du Probleme hast, für den MSMQ-Kanal passende ProtocolSetups für Zyan zu schreiben, helfe ich Dir gerne weiter.
Meine MSMQ-Kenntnisse sind eher theoretischer Natur. Aber ich versuche trotzdem Zyan über MSMQ bei mir zum Laufen zu bringen. Zunächst mal rein experimentell.
Ob Zyan in Verbindung mit MSMQ wirklich sinnvoll ist, wage ich zu bezweifeln. Alleine die Tatsache, dass man bei MSMQ erst auf allen PCs installieren und von Hand (oder über ein Setup-Programm) erst irgendwelche Queues erstellen muss, wiederspricht schon der Grundphilosophie von Zyan. Zyan soll so admin- und konfigurationsfrei wie möglich sein. Das ist bei MSMQ schon nicht gegeben.
Was würde denn passieren, wenn jemand eine Client-Anwendung mit MSMQ z.B. auf einem Terminalserver betreiben würde? Dann müsste doch für jede Instanz der Clientanwendung eine eigene Empfangsqueue angelegt werden, oder?
Dieser Beitrag wurde 3 mal editiert, zum letzten Mal von Rainbird am .
ich habe einen Branch mit MSMQ-Integration von Zyan angelegt. Leider konnte ich nicht Testen, ob er funktioniert, da der MSMQ Remoting Kanal von Roman Kiss nur Active Directory aktiviertes Message Queuing unterstützt. Extra Test-VMs mit Domänencontroller aufzustzen ist mir aber momentan zu viel Aufwand für ein Feature, das vermutlich keine große Verbreitung finden wird.
Den Quellcode findest Du hier http://zyan.codeplex.com/SourceControl/changeset/changes/8916. Und zwar im Ordner branches\msmq_integration. Der neuste MSMQ-Kanal von Roman Kiss ist da schon fix und fertig in Zyan integiert. Wenn Du möchtest kannst Du die MSMQ-Integration gerne auf diesem Branch aufbauend testen, debuggen und ggf. weiterentwicklen. Wenn Du es am laufen hast, kannst Du Deine Version als Patch zu diesem Branch bei Codeplex hochladen. Ich merge den Patchcode dann.
Wenn Dir beim aktuellen Stand der MSMQ-Integration etwas unklar ist, kannst Du mich aber trotzdem gerne fragen.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Rainbird am .
... planst du, das IQueryable<T> unterstützt wird? Momentan fliegt sofort eine SerializationException (System.Linq.EnumerableQuery<T> nicht serialisierbar). Sonst läuft das echt gut.
Zyan unterstützt jetzt auch verteilte LINQ-Abfragen. Die LINQ-Unterstützung ist im Projekt Zyan.InterLinq implementiert. Du musst diese Assembly zusätzlich zu Zyan.Communication als Verweis zufügen, wenn Du mit verteilten LINQ-Abfragen arbeiten willst.
So fühlen sich verteilte LINQ-Abfragen mit Zyan an:
// Verbindung zum Zyan-Server herstellen
var conn = new ZyanConnection("tcp://localhost:8085/InterLinqTest")
// Abfrageaktivierter Proxy erzeugen
var proxy = conn.CreateQueryableProxy("CustomerQueryProvider");
// LINQ-Abfrage ausführen, die serverseitig verarbeitet wird
var customers = from customer in proxy.Get<Customer>()
where customer.CustomerID == 1
select customer;
Linq2Sql und Entity Framework sollten auch kein Problem sein.
Wer das Endergebnis mal ausprobieren möchte, kann sich den kleinen MiniChat-Client im Anhang runterladen. Es handelt sich um ein Instant Messaging Beispiel, welches mit einer zentralen Zyan-Serverkomponente arbeitet, die in Azure gehostet wurde.
Einfach im Login-Fenster einen beliebigen Nickname eingeben und als Server-URL 'tcpex://ZyanMiniChat.cloudapp.net:9010/MiniChat' auswählen. Über die Instanzen des MiniChat-Clients kann man sich weltweit miteinander unterhalten.
Danke für den Hinweis. Ich habe einen Starken Namen für Zyan 2.2 eben auf die TODO-Liste gesetzt. Hier kannst Du den Status der Entwickleraufgabe verfolgen: http://zyan.codeplex.com/workitem/1231
Bis zum release von Zyan 2.2 kannst Du Dir behlfen indem Du die Quellen von Zyan herunterlädst und zum Projekt Zyan.Communication selber einen SNK-Schlüssel zufügst und das Projekt anschließend neu kompilierst.
Für .NET 4.0, .NET 3.5 und mono gibt es getrennte SLN Dateien im Ordner \source.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Rainbird am .
ich habe mehrere Verbindungen zum Zyan-Server aufgebaut (uns sie nach Verwendung wieder Dispose).
Nun bekomme ich jedoch den Fehler:
Fehler
Ein Socketvorgang konnte nicht ausgeführt werden, da dem System Pufferspeicher fehlte oder eine Warteschlange voll war
Woher kann das kommen? Ich habe schon gelesen, dass es vorkommt, wenn man einen Port ≥ 5000 verwendet oder wenn zu viele gleichzeitige Verbindungen offen sind.
ich habe den Fehler - hoffentlich - behoben. Problemursache war, dass der Client-Remotingkanal bei Aufruf von Dispose nicht richtig deregistriert wurde.
für das Kommunikationsframework Zyan wurde soeben die neue Version 2.2 veröffentlicht. Neben jeder Menge Bugfixes bringt die neue Version folgende Neuerungen mit:
Setzt ihr Zyan in Real-World-Projekten ein?
Falls ja, würde ich mich über eine kurze Rückmeldung im Zyan-Diskussionsbereich Projects using Zyan Framework(Thread ist allerdings in Englisch!) sehr freuen.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Rainbird am .
ich verwende die aktuelle Version (2.3) und habe vllt. einen "Fehler" festgestellt.
Ich habe einen Server, der eine Funktion implementiert, die als Parameter eine List<T1> erwartet und eine List<T2> zurück gibt.
public List<T2> Function<T1, T2>(List<T1> list)
Wenn ich vom Client jedoch diese Funktion aufrufe, bekomme ich die Fehlermeldung
Fehler
Methode nicht gefunden
Ich habe einen Test gemacht, ob es vllt. daran liegt, dass ich zwei verscheiden Typen verwende (T1 und T2) und habe nur T1 verwendet. Da kan allerdings der gleiche Fehler.
Wenn ich in der Funktion jedoch den Typ fest angebe, dann funktioniert es.
public List<T1> Function<T1>(List<Article> list)
Woran kann es liegen, dass ich keinen anonymen Typparameter als Funktionsparameter benutzen kann?
Gruß
..Heinz..
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von ..Heinz.. am .
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.
Zitat von ..Heinz..
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.
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?
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?
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
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von Rainbird am .
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.
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.
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.
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.