Laden...
Avatar #avatar-2834.jpg
Rainbird myCSharp.de - Experte
Fachinformatiker (AE) Mauer Dabei seit 28.05.2005 3.728 Beiträge
Benutzerbeschreibung
Ich mag Tee lieber als Kaffee.

Forenbeiträge von Rainbird Ingesamt 3.728 Beiträge

13.06.2011 - 17:55 Uhr

Hallo mogel,

warum willst Du überhaupt zwei Hosts haben? Wenn Du einen zentralen Einstiegspunkt benötigst, was liegt da näher, als alles in einem einzigen Host zu veröffentlichen?

Zwei Hosts machen eigentlich nur dann Sinn, wenn man einen Komponentenkatalog über verschiedene Protokolle (z.B. TCP und HTTP) gleichzeitig veröffentlichen möchte. Z.B. so:

TcpDuplexServerProtocolSetup tcpDuplexProtocol = new TcpDuplexServerProtocolSetup(8081, new NullAuthenticationProvider(), true);
HttpCustomServerProtocolSetup httpProtocol = new HttpCustomServerProtocolSetup(8080, new NullAuthenticationProvider(), false);

ComponentCatalog catalog = new ComponentCatalog();
catalog.RegisterComponent<IMyComponent, MyComponent>();

ZyanComponentHost tcpHost = new ZyanComponentHost("MyAppTcp", tcpDuplexProtocol, catalog);
ZyanComponentHost httpHost = new ZyanComponentHost("MyAppHttp", httpProtocol, catalog);

Edit: Wenn ein Windows-Prozess einen Socket auf einem bestimmten Port öffnet, ist dieser Port für andere Prozesse gesperrt. Das ist generell so. Falls Du also Komponenten, die in verschiedenen Server-Prozessen laufen über einen einzigen Port ansprechen willst, geht das nur über einen zentralen "Routing-Server".

13.06.2011 - 14:17 Uhr

Das war auch mein erster Gedanke. Im Prinzip ist es wirklich nicht wichtig den Zeitpunkt des Ab/Anmeldens in den EventArgs mitzugeben, da zwischen Auftreten des Events und Behandlung des Events keine nennenswerte zeit vergeht.

11.06.2011 - 17:47 Uhr

Wäre es nicht besser in den LoginEventArgs des ClientLoggedOff-Ereignisses die aktuelle Systemzeit anstelle von Session.Timestamp (beinhaltet den Zeitpunkt der Anmeldung) zu übermitteln?

Ich möchte an der Stelle alle wichtigen Daten der Session haben. Dazu gehört aus der Zeitstempel der letzten Sitzungsverlängerung.

Aber die aktuelle Serverzeit beim auftreteten des Events könnte ich zusätzlich noch mitschicken.

11.06.2011 - 14:55 Uhr

Hallo Equilibrium,

welche Version von Zyan hast Du im Einsatz?
Falls Du noch min Zyan 1.x arbeitest, solltest unbedingt auf Zyan 2.0 umstellen. Der Verdrahtungscode wurde dort komplett überarbeitet.

Zyan 2.0 bekommst Du hier: http://zyan.codeplex.com/releases/view/62104

Falls das Problem mit Zyan 2.0 auch auftritt, versuche ich es bei mir zu reproduzieren und werde Dir Bescheid geben, wenn es eine Lösung gibt.

Edit: Habe eben eine kleine Testanwendung geschrieben, konnte den Fehler aber nicht reproduzieren (Verwendete Zyan Version: 2.0). Das BenutzerListenElemente-Objekt wurde bei mir ohne Probleme serialisiert. Code der Testanwendung findest Du in der ZIP-Datei im Anhang.

Du solltest folgendes Überprüfen:*Liegen auf Client und Server verschiedene Versionen der Shared-Assembly? (Beide Kommunikationspartner müssen über die selben gemeinsamen Assemblies verfügen; Also wirklich identische Version) *Tritt das Problem in Verbindung mit Callbacks oder Events auf? *Welche .NET Framework-Version verwendest Du?

Gruß

Raibird

08.06.2011 - 00:46 Uhr

Die finale Version von Zyan 2.0 ist fertig.

Hier gibts die Bianries zum runterladen: http://zyan.codeplex.com/releases/view/62104

07.06.2011 - 08:14 Uhr

Hallo zusammen,

Zyan-Anwendungen lassen sich nun auch mühelos in Windows Azure hosten. Weitere Details dazu: http://zyan.codeplex.com/discussions/259397

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.

Den kompletten Quellcode inklusive Azure Hosting gibts im Zyan Quellcode Repository (http://zyan.codeplex.com/SourceControl/list/changesets) im Order examples\Zyan.Examples.AzureHosting.

Viel Spaß beim ausprobieren.

03.06.2011 - 07:11 Uhr

Hallo Campy,

die Antwort kommt zwar etwas spät, aber besser spät als nie.
Bei einem proeritären Protokoll kommen wohl nur Sockets (bzw. TcpClient) in Frage.

03.06.2011 - 05:55 Uhr

Hallo rimiko,

freut mich, dass Dir meine Arbeit nützlich ist.

Ich habe eine neue Zyan-Version eingecheckt. Du kannst Dir den aktualisierten Quellcode unter http://zyan.codeplex.com/SourceControl/list/changesets runterladen.

Die Klasse ZyanComponentHost hat nun zwei neue Ereignisse namens ClientLoggedOn und ClientLoggedOff. Außerdem kannst Du nun über ServerSession.CurrentSession.ClientAddress auch die Client-IP-Adresse abfragen.
Ich habe das MiniChat um die neuen Features erweitert (Liegt im Repository unter examples\Zyan.Examples.MiniChat

Gruß

Rainbird

29.05.2011 - 22:03 Uhr

Hallo rimiko,

es gibt momentan noch kein Event, um sich an zentraler Stelle über einen Logoff informieren zu lassen.

Du kannst es aber in einem benutzerdefinierten SessionManager implementieren. Dazu musst Du Zyan.Communication.SessionMgmt.ISessionManager implementieren. Wenn sich ein Client abmeldet, wird von der Zyan-Infrastruktur die Methode "RemoveSession" aufgerufen.

Am einfachsten kopierst Du Dir den Quellcode des Standard-SessionManager (Klasse Zyan.Communication.SessionMgmt.InProcSessionManager) in eine eigene SessionManager-Klasse und baust ihn nach Deinen eigenen Wünschen um. Deinen eigenen SessionManager musst Du dem Konstruktur des ZyanComponentHost-Objekts als Parameter mitgeben.

Ich werde ein Logoff und Logon Event nachrüsten. Kann aber ein bischen dauern. Trotzdem ist der SessionManager der richtige Ort für solche Anpassungen.

Gruß

Rainbird

29.05.2011 - 02:20 Uhr

Hallo Equilibrium,

Zyan ist die Weiterentwicklung des Projekts ".NET Applikationsserver". Zyan kann inzwischen schon viel mehr, als der "kleine" .NET Applikationsserver: Duplex-Kommunikation, Erweiterbare Sitzungsverwaltung, Verschlüsselung, LINQ-Abfragen übers Netzwerk, Policy Injection, Call Interception, ...

Es laufen auch schon Tests zum Hosting von Zyan in Microsoft Azure (Cloud Computing). http://zyan.codeplex.com/discussions/259397

Zyan läuft auch grundsätzlich unter mono, wobei viele noch Features nicht mit mono getestet wurden.

Gruß

Rainbird.

29.05.2011 - 02:07 Uhr

Hallo Alphawolf1988,

Wie ist das, wenn der Client B ebenfalls ein weiterer Server B mit ServerObjekt B ist und dieser wiederrum erst durch Clienten C benutzt wird.

Das geht mit Remoting ohne Probleme.

Also ich rufe eine Funktion von Server B auf und dieser eine Funktion von Server A. Server A gibt an B ein Objekt von MarshalByRef zurück und B gibt dieses weiter an Client C.

Ist dies überhaupt möglich? Ja. Warum soll es denn nicht möglich sein? Streiche mal das Client und Server aus Deinen Gedanken. Du hast Prozesse, die miteinander kommunizieren. Diese Prozesse können (müssen nicht) auf verschiedenen Computern laufen. Angenommen Du hast drei Prozesse A, B und C. Prozess A ruft eine Methode in Prozess B auf. Prozess B ruft wiederum eine Methode von Prozess C auf. Prozess C verarbeitet die Methode und sendet den Rückgabewert zurücl zk B. B sendet seinen Rückgabewert zurück an A. Fertig.

Es könnte aber auch anders laufen: A übergibt einen Verweis auf ein von MarsahlByRef abgleitetes Objekt als Parameter an B. B gibt den Parameter weiter an C. C ruft einen Callback über den erhaltenen Parameter auf, welcher direkt auf A durchschlägt.

Remoting ist sehr vielseitig und kann solche Sachen ohne Probleme und ohne Kopfstände. WCF kann das per Design definitiv nicht. Warum? Weil man bei WCF keine Objektreferenzen übergeben kann. WCF sendet nur Nachrcihten (Daten). Also das, was man bei Remoting als [Serializable] markiert. So etwas wie MarshalByRefObject gibt es in der WCF-Welt nicht.
Der RoutingService von WCF funktioniert anders. Der leitet Nachrichten abhängig vom Inhalt oder bestimmten Merkmalen an bestimmte Services weiter bzw. um. Bei WCF muss man immer alles "explizit" machen. das heißt man muss vieles "irgendwie" in die Hand nehmen, damit sich was tut. Remoting bildet einfach Methodenaufrufe übers Netzwerk ab. So natürlich und intuitiv wie möglich. Das sind zwei ganz verschiedene herangehensweisen.

Obwohl Remoting all solche Dinge kann, musst Du stets gut überlegen ob und wann Du was davon einsetzen willst. Der Einsatz von Events und Callbacks z.B. berauben Dich z.B. jeglicher Möglichkeit für Sacle-Out über mehrere Applikatonsserver, da sich der Client durch das statuswahrende Event-Abo fest an einen bestimmten Server bindet. Features wie Netzwerklastenausgleich etc. funktionieren dann nicht mehr. Wenn Du allerdings niemals sowas wie einen NLB-Cluster brauchen wirst und mit einem einzelnen Server lange auskommst, ist die Event-Geschichte kein Problem und auch nix böses. Und so ist es mit allem. Es kommt drauf an was Du genau machst und welche Anforderungen Du hast. Für einige Fälle werden bestimmte Remoting-Features super geeignet sein, für andere nicht. Für andere Fälle bekommst Du vielleicht mit WCF die besten Ergebnisse.

Was willst Du denn genau machen?

Gruß

Rainbid

10.05.2011 - 10:55 Uhr

Hallo Lynix,

Du könntest auch eine COM-Bibliothek schreiben, welche ein schönes API für den Client anbietet. Dort handelst Du dann die TCP-Kommunikation ab.
In VBScript würde sich das dann in etwa so anfühlen;

Dim objServer
Set objServer = CreateObject("MyComWrapper.Server")
objServer.Connect("192.168.0.10")

objServer.Start

Du müsstest die COM-Wrapper DLL allerdings auf alle Clients ausrollen und registrieren.

05.05.2011 - 07:55 Uhr

Hallo Campy,

WCF kommt hauptsächlich im SOAP/REST-Umfeld zum Einsatz. Natürlich gibt es auch das binäre und performante NetTcpBinding, aber dieses ist nicht interoperabel.

TcpClient und TcpListener sind für gewöhnlich das Mittel der Wahl. Da Deine Clients keine .NET Clients sind, fällt .NET Remoting und Zyan als Empfehlung weg. Es sei denn auf Deinen Clients läuft auch Mono. Dann würde auch .NET Remoting / Zyan funktionieren.

Wie kommunizieren die Endgeräte denn? Protokoll?

27.04.2011 - 12:27 Uhr

Hallo Zusammen,

ich habe eine Beta-Version von Zyan 2.0 veröffentlicht. Hier gibts die neue Version zum runterladen: http://zyan.codeplex.com/releases/view/65159

Highlights der 2.0er Version sind:*TCP Duplexkanal für Kommunikation durch clientseitige NAT-Firewalls hindurch *LINQ Unterstützung *Call Interception System *Unterstützung für Delegat-Parametern

Ich würde mich über Feedback freuen.

Viel Spaß beim Ausprobieren der Beta.

11.04.2011 - 21:49 Uhr

Hallo Friedel,

direkte Kommunikation über Remoting (und damit auch Zyan, da dies auf Remoting aufgebaut ist) geht mit dem Compact Framework leider nicht. Für die Remoting-Unterstützung fehlen wesentliche Features wie Reflection und Binärserialisierung.

Es gibt allerdings eine kommerzielle Bibliothek, die .NET Remoting fürs Compact Framework nachrüstet: http://gotcf.net/Default.aspx

Ist allerdings nicht kostenlos. 499 US$ für eine Entwicklerlizenz und 10 CE-Gerätelizenzen.

Alternativ kannst Du Webservices verwenden, um zentral Funktionalität für Deine CE-Geräte anzubieten. Das ist zwar in Sachen Komfort von Zyan weit entfernt, aber dafür mit CF Bordmitteln machbar.

Für eine zukünftige Zyan Version ist ein Silverlight-Client angedacht. Bisher ist das allerdings nur eine Idee. http://zyan.codeplex.com/workitem/783

Wenn Du sowohl volle .NET-Clients als auch CF-Clients hast, kannst Du Zyan auch für die vollen .NET Clients einsetzen und die Zyan-Komponenten mit Webservices für die CF-Clients wrappen.

Gruß

Rainbird

11.04.2011 - 00:40 Uhr

Hallo Friedel,

Endlich mal ein Framework in dieser Richtung, welches einem einiges abnimmt. Dafür schon mal Dank an Rainbird und Co.

Schön dass Dir das Zyan Framework gefällt.

  1. Kann man mit Zyan auch komplexe Typen benutzen?

Zyan "denkt" in Komponenten, nicht in Objektmodellen. Du kannst nur auf Komponenten zugreifen, die Du vorher mit RegisterComponent veröffentlicht hast. Rückgabewerte von Eigenschaften dieser Komponenten werden nicht automatisch auch als Komponenten veröffentlicht.

Generell solltest Du serverseitig so statuslos wie möglich programmieren. Zyan trägt dem Rechnung indem Komponenten standardmäßig SingleCall-aktiviert veröffentlicht werden. Das heißt, für jede Clientanfrage wird eine separate Instanz erzeugt und nach Verarbeitung der Anfrage gleich wieder entsorgt. So bleibt der Server völlig statuslos, skaliert optimal und kann auch in Verbindung mit Enterprise-Features wie Netzwerklastverteilung eingesetzt werden.
Alternativ kann man Komponenten Singleton aktiviert veröffentlichen. Dabei wird eine gemeinsame Instanz der Komponente erzeugt und zur Verarbeitung aller Clientanfragen verwendet (Singleton Komponenten müssen deshalb threadsicher programmiert werden). Singleton-Instanzen leben solange, wie der Komponentenkatalog existiert. Es wird nicht - wie bei Remoting - mit Leases und Sponsoren gearbeitet. Clientaktivierte Objekte unterstützt Zyan überhaupt nicht. Und das ist auch gut so. Die wären nämlich Gift für die Skalierbarkeit.

Du solltest nicht klassisch objektorientiert denken, wenn es um verteilte Anwendungen geht. Die Objektorientierung predigt Vereinigung von Logik und Daten in Klassen. In einer verteilten Umgebung taugt dieser Ansatz nichts. Da musst Du Logik und Daten strikt voneinander trennen. Und die Logik vorzugsweise statuslos halten. Wenn Du doch mal Status brauchst, bietet Zyan dafür Sitzungen und Sitzungsvariablen an (wie z.B. bei ASP.NET üblich).

Ich würde gerne so etwas machen:

  
Shared.IEchoServer proxy = connection.CreateProxy<Shared.IEchoServer>();  
proxy.SubClass.Name = "4567";  
string s = proxy.SubClass.Name; // = "1234"  
  

Welchen Wert sollte proxy.Subclass.Name haben, wenn ein anderer Client die Eigenschaft abfrägt?
Ich kann Dir nur von dieser Vorgehensweise abraten (unabhängig davon, ob man das mit Zyan hinbekommt, oder nicht; Für Zyan 3.0 ist ein Feature geplant, um Komponentenreferenzen zurück zum Client geben zu können). Du hättest dabei den Status auf dem Server. Der Status sollte beim Client liegen.

Die Eigenschaft 'SubClass' gibt eine Referenz einer simplen Klasse zurück und diese hat eine Eigenschaft Name, welcher per Default auf "1234" gesetzt ist. Weise ich der Eigenschaft jetzt "4567" zu und rufe diese erneut ab, ist der Wert immer noch "1234". Geht das per se nicht, oder muss dafür etwas spezielles beachtet werden.

Standardmäßig wird Deine Komponente SingleCall aktiviert veröffentlicht. Sie lebt also immer nur einen Methodenaufruf lange und vergisst danach alles (was nicht persistiert wurde, oder eine Sitzungsvariable ist). Du könntest die Aktivierungsart auf Singleton ändern (bei RegisterComponent als Parameter angeben). Damit wäre das Problem, dass Subclass nicht als Komponente registriert ist, aber noch nicht gelöst.

  1. Wie verhält es sich mit der Lebensdauer eines Remoting-Objekts und was passiert, wenn das Gerät (CE-Device) eine neue IP-Adresse zugewiesen bekommt?

Lebensdauert für ...
... SingleCall-Komponenten: 1 Methodenaufruf lang
... Singleton-Komponenten: Solange der Komponentenkatalog existiert, in welchem die Komponenten registriert wurden.

Solange Du weder Events noch Callbacks verwendest, sollten wechselnde IP-Adressen kein Problem sein. Falls Du aber Events/Callbacks verwendest, könnte es sein, dass nach dem Wechsel der IP-Adresse Events nicht mehr gefuert und Callbacks nicht mehr aufgerufen werden, da die zwischengespeicherte Rückrufadresse ja nicht mehr stimmt. Nur wenn alle beteiligten Geräte über DNS-Namen verfügen, können Events/Callbacks auch nach einem Adresswechsel korrekt angesprochen werden. Das TcpDuplexProtocolSetup hat momentan genrell noch Probleme mit wechselnen IP-Adressen (ist ja aber auch noch nicht ganz fertig).

Wenn Du mir genauer beschreibst, was Du mit Zyan machen wilst, kann ich Dir detailliertere Vorschläge machen.

06.04.2011 - 08:24 Uhr

Hallo telnet,

Erster Versuch war jetzt, ein DataSet als Returntype zu verwenden, was weder schön ist noch funktioniert 😉

Warum hat es nicht funktioniert? DataSets funktionieren ohne Probleme mit WCF zusammen?

Warum findest Du, dass es nicht schön ist, DataSets einzusetzen? DataSets tun genau das, was Du suchst. Statt sie zu verwenden willst Du lieber selber mit XML rumwursteln?

29.03.2011 - 08:15 Uhr

Hallo Oliver Stippe,

hier findest Du jede Menge Linq2DataSet Beispiele: MSDN: Linq to DataSet Samples

28.03.2011 - 06:50 Uhr

Hallo Sanny,

ich finde nicht, dass es zum Durcheinander führt. Im Gegenteil. Microsoft tut bei Typisierten DataSets dasselbe. Wenn Du z.B. eine Instanz der DataTable Address im DataSet ContactManagement erzeugen willst, musst Du auch ContactManagementDataSet.AddressDataTable verwenden.

Ich finde das gut. So weißt Du ganz intuitiv wozu die DataTable gehört und wovon sie ggf. durch definierte Beziehungen abhängig ist. Bei Deinen eigenen Klassen ist das ganz genauso. Wenn eine Klasse von einer übergeordneten Klasse in so einer Weise abhägig ist, spricht nichts dagegen, sie als verschachtelte Klasse zu definieren.

Dem Compiler ist es auch völlig egal, ob jede Klasse in einer separaten Datei ist oder nicht. Auch wenn der eine oder andere das Datei-pro-Klasse-Credo als unumstößliches Gesetz sieht, muss das für andere noch lange nicht gelten. Das es generell unübersichtlich macht, mehrere Klassen in eine Datei zu packen, möchte ich bestreiten. Wenn es sich bei der "beigepackten" Klasse (unabhängig davon ob verschachtelt oder nicht) um Kleinkram handelt, finde ich es sogar sehr von Vorteil, wenn dafür nicht auch noch eine Datei im Projektmappen-Explorer auftaucht. Am Ende kann man das aber unter Geschmacksache verbuchen.

13.03.2011 - 15:22 Uhr

Hallo Khalid,

... 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.

Weitere Infos zum LINQ Support von Zyan findest Du in folgendem Beitrag im Diskussionsbereich der Zyan Projektseite: http://zyan.codeplex.com/discussions/249427

In der aktuellen Release 1.2 ist die LINQ-Unterstützung noch ++nicht ++enthalten. Du musst Dir also den Quellcode hier runterladen http://zyan.codeplex.com/SourceControl/list/changesets .

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.

Unter examples\Zyan.Examples.Linq in http://zyan.codeplex.com/SourceControl/changeset/view/9440# findest Du ein Beispielprojekt.

11.03.2011 - 00:44 Uhr
  1. Soll ich die Datenübertragung selbst über den WCF Service steuern, oder mir nur Informationen über neue Jobs von der Datenbank via WCF Service holen und dann die Übertragung separat initiieren z.B. durch TcpClient, also den WCF Service gänzlich außen vor lassen?

Ich würde alles über die Server-API abwickeln. Das erleichert Administration und Deployment. Die Clients müssen dann nur die Serveradresse kennen, sonst nichts.

  1. Kann ich im WCF Service Events definieren, damit der Client benachrichtigt werden kann wenn der Server einen neuen Job für ihn erstellt hat, oder ganz einfach gefragt, was wäre hierfür die beste herangehensweise?

WCF unterstützt keine Events. Man kann aber einen DuplexContract einrichten, der Callbacks möglich macht.

Es geht aber auch einfacher. Nicht mit WCF sondern mit Zyan. Mit Zyan sind verteilte Ereignisse sehr einfach und komfortabel umsatzbar. Hier ein Beispiel: http://zyan.codeplex.com/wikipage?title=Ereignisse%20verteilt%20einsetzen&referringTitle=Deutsche%20Dokumentation

Zyan ist kostenfrei und quelloffen.

P.S.: Zyan ist allerdings nur dann eine Option, wenn Client und Server .NET/mono Anwendungen sind.

11.03.2011 - 00:26 Uhr

Hallo WasserDragoon,

für OpenLigaDB müssen es natürlich Webservices sein. Da scheiden Remoting und Zyan aus. Hatte das falsch verstanden, da der Titel des Threads WCF oder TCP ist.

10.03.2011 - 13:55 Uhr

Hallo WasserDragoon,

WCF ist unter mono nicht vollständig implementiert. Du kannst aber Remoting verwenden. Das braucht auch kein WSDL etc. Nur ein bisschen C# Code.

Alternativ kannst Du auch Zyan verwenden. Damit wird die Netzwerkprogrammierung besonders einfach.

http://zyan.codeplex.com

10.03.2011 - 13:48 Uhr

Hallo UweR,

Du kannst Dir mal Genuine Channels anschauen. Damit kann der Server über bestehende Verbindungen Callbacks auf den Clients durchführen. Um das Threadpooling kümmert sich die Remoting Infrastruktur. Mehrere hundert Clients sollten kein Problem sein.

http://www.genuinechannels.com/

25.02.2011 - 08:22 Uhr

Gibt es einen Unterschied zwischen der Anmeldung am Server mit einem Windows-Konto und einem Domänen-Konto?

Ja. Ein Windows-Konto ist nur für einen einzelnen Windows-Computer gültig. Windows-Konten werden lokal in der SAM-Datenbank des Windows-Computers gespeichert. Ein Server kann mit einem Windows-Konto nichts anfangen, da er logischerweise keinen Zugriff auf die lokale SAM-Datenbank des Clients hat.

Domänen-Konten werden in Active Directory in zentralen LDAP-Datenbanken auf den Domänencontrollern der Domäne gespeichert. Ein SQL Server kann die Anmeldung eines Clients, der ein Domänen-Konto hat, durch eine Anfrage beim zuständigen Domänencontroller prüfen lassen.

Zusammenfassung:

Windows-Konten = nur lokal gültig
Domänen-Konten = netzwerkweit gültig, da in zentraler LDAP-Datenbank gespeichert

Es gibt auch eine Möglichkeit, mit Windows-Konten im Netzwerk zu arbeiten. Dafür müssen auf allen beteiligten Computern ++identische ++Benutzernamen und ++identische ++Passwörter erstellt werden! Als Protokoll kann dann auch nicht mehr Kerberos verwendet werden, sondern nur NTLM (NT LAN Manager). Windows handelt das Auth-Protokoll normalerweise automatisch aus.

In einem Produktivnetzwerk würde ich dringend von diesem Holzbein-Workaround abraten.

22.02.2011 - 01:44 Uhr

Hallo zack0r,

Du brauchst innerhalb des Servers keine ZyanConnection. Du kannst direkt über den Komponentenkatalog gehen. Das ist auch schneller. Hier hatte schon jemand eine ähne Frage: Komponenten kommunikation

21.02.2011 - 20:12 Uhr

Hallo zack0r,

Wenn man mit Virtual Studio ein Interface implementiert, dann benutzt er die Schreibweise "DataSet IMasterService.GetAll()" anstatt "public DataSet GetAll()" und dabei gibts ein Problem.

Bei mir setzt Visual Studio das public automatisch. Getestet mit Visual Studio 2010. Welche Visual Studio Version hast Du im Einsatz?

Davon abgesehen, ist das kein Zyan-Bug. Zyan kann nichts dafür, dass das Visual Studio-Schnittstellenwekzeug bei Dir den Zugriffsmodifizierer nicht angibt. Damit man eine Methode von außen aufrufen kann, muss sie nun mal public sein. Das ist generell so.

Den Client-User kann ich vermutlich mit Zyan.Communication.ServerSession.CurrentSession auslesen richtig?

Ja, aber nur serverseitig. Also nicht vom Client aus. Um die Identität des Aufrufers abzufragen, verwendest Du:


IIdentity userIdentity = ServerSession.CurrentSession.Identity;

Momentan steht die aktuelle ServerSession also nur serverseitig zur Verfügung. Man könnte die Daten der ServerSession auch clientseitig gut gebrauchen. Ich werde das in Zyan einbauen. Macht Sinn.

Geht das nur wenn ich einen anderen Authentication Provider als NullAuthenticationProvider benutze?

Zyan erstellt immer einer Sitzung. Der AuthenticationProvider bestimmt nur, wie die Identität der Benutzer geprüft wird. Aber auch beim NullAuthenticationProvider wird trotzdem eine Sitzung erstellt. Die Identity-Eigenschaft der Sitzung wird beim NullAuthenticationProvider immer auf den Anonymen Windowsbenutzer (ANONYMOUS-ANMELDUNG) gesetzt.

Für Deinen Anwendungsfall ist vermutlich der BasicWindowsAuthProvider interessant. Der prüft die vom Client übergebenen Credentials (Benutzername, Kennwort und Domäne) gegen die Windows-Sicherheit der Servers (Wenn kein AD verwendet wird, kann man als Domäne den Computernamen des Servers als Domäne angeben). Identity ist dann eine GenericIdentity mit dem Windows-Benutzernamen.

21.02.2011 - 18:31 Uhr

Hallo JuyJuka,

die Steuerelemente sollen auch im Designer sichtbar sein und dort angepasst werden können.

Du hast Recht: Für die protected Steuerelemente sind in der Ressource der abgeleiteten Form die Einträge nochmal drin. Allerdings nur in der Standardsprache. In den lokalisierten Ressourcen fehlen die Einträge komplett. Das erklärt auch das Verhalten. Er sucht die Einträge in der Ressource des geerbten Forms und findet sie nicht. Also fällt er bei den betroffenen Einträgen zurück auf die Standardsprache (in meinem Fall Englisch).

Dann muss ich wohl die Beschriftungen der Steuerelemente auf dem Basisformular per Code lokalisieren.

21.02.2011 - 11:59 Uhr

Hallo Zusammen,

ich habe Probleme mit lokalisierten (mehrsprachigen) Windows.Forms-Formularen, die visuelle Vererbung verwenden. Die Steuerelemente des Basisformulars werden im abgeleiteten Formular immer mit der Standardsprache angezeigt. Außerdem springt die Schriftart (Font-Eigenschaft) im abgeleiteten Formular immer auf "MS Sans Serif" zurück, wenn ich im Designer auf eine andere Sprache umschalte.

Ich bin folgendermaßen vorgegangen um das Basisformular zu erstellen:*Neues Formular mit Visual Studio erzeugt *Steuerelemente zugefügt und in Englischer Sprache beschriftet *Modifier der Steuerelement auf Protected gesetzt, damit sie in abgeleiteten Formularen später voll zugreifbar sind *Schriftart von "MS Sans Serif" auf "Tahoma" geändert *Fenstersymbol geändert *Localizable auf True eingestellt *Als Sprache im Designer (Langauge-Eigenschaft) auf "Deutsch" umgestellt *Steuerelemente und Formulartitel auf Deutsch übersetzt *Gespeichert *Projekt kompiliert

Dann habe ich, wie folgt, ein geerbtes Formular davon erstellt:*In Visual Studio Neues Element "Geerbtes Formular" zugefügt *Im folgenden Auswahldialog das zuvor erstelltes Basisformular ausgewählt *Zusätzliche Steuerelement zugefügt und in Englischer Sprache beschriftet *Localizable auf True eingestellt *Als Sprache im Designer (Langauge-Eigenschaft) auf "Deutsch" umgestellt *Steuerelemente und Formulartitel auf Deutsch übersetzt *Gespeichert *Projekt kompiliert

Sowohl im Designer als auch zur Laufzeit werden die geerbten Steuerelemente im Deutschen Windows fälschlicherweise Englisch und die Nichtgeerbten korrekt auf Deutsch dargestellt.

Kennt jemand von euch das Problem?
Gibt es vielleicht einen Trick, um dem Windows.Forms-Designer auf die Sprünge zu helfen?

Wichtig! In dem Projekt wird noch Visual Studio 2008 verwendet.

Danke im Vorraus.

21.02.2011 - 09:16 Uhr

Hallo zack0r,

Fällt dir dazu was ein?

Mit Zyan ist das kein Problem. Da würdest Du einfach das TcpCustomServerProtocolSetup verwenden und die Clients würden automatisch gegen die Benutzerdatenbank des Servers (ob AD oder nicht) authentifiziert werden.

Wenn Du Zyan in einsetzen kannst/willst, kannst Du Dir den Code nötigen Code dafür aus dem Zyan-Quellcode rauskopieren und in Deine Remoting-ANwendung integrieren.

18.02.2011 - 19:45 Uhr

Hallo spike24,

aber mir fehlt die Rollback Methode.

Die brauchst Du nicht. Ein Rollback wird automatisch dann gemacht, wenn scope.Complete() nicht aufgerufen wird (also z.B. auch bei einer Ausnahme). Wenn Du einen Rollback haben willst, dann lasse einfach nicht zu, dass scope.Complete aufgerufen wird.

System.Transactions unterstützt auch verteilte Transaktionen (Transaktionen, die über mehrere Datenbankserver hinweg aufgespannt werden).

System.Transactions.Transaction ist auch serialisierbar. So kannst Du z.B. eine Transaktion auf dem Client-Computer starten und dann Logik auf einem Applikationsserver mit in die Transaktion reinnehmen. System.Transaction stuft die Transaktion dann automatisch in einen verteilten Ausführungsmodus hoch, der einen 2-Phasen Commit verwendet. Damit verteilte Transaktionen laufen, brauchst Du einen unterstützten laufenden Transaktionsmonitor (z.B. den Microsoft Distributed Transaction Coordinator, kurz MSDTC, der in Windows enthalten ist).

auch fehlen mir Events (Commiting -> für eine Validierung, Commited -> weis ich noch nicht für was, Rolledback ->weis ich auch noch nicht)

Was willst Du beim Commit validieren?

und bei einem Commit muss ich über ein Interface zur ObjectStoreService, das werd ich dem TransactionScope auch nicht beibringen können.

Du rufst deinen ObjectStoreService einfach nach scope.Complete() auf. Dann weisst Du, dass die Transaktion commited wurde.

Wenn Du unbedingt Commit und Rollback manuell aufrufen willst, gibt es dafür die CommittableTransaction.

Das Blöde daran ist, die die daran teilnehmen sollen, wissen nicht dass sie daran teilnehmen wollen. Momentan ist es so gelöst dass das BusinessObject nicht weis dass es Transactions gibt.

Die Businessobjekte müssen das auch nicht wissen. Der TransactionScope hängt die Transaktionskennung an den aktuellen Thread. Jede ADO.NET-Connection, die in diesem Thread dann geöffnet wird, nimmt automatisch an der Transaktion teil. It´s magic. Wenn Du etwas explizit nicht in die Transaktion aufnehmen willst, machst Du einen eigenen TransactionScope mit der Option Suppress drum. Dann wird die Transaktion für alles in diesem Block nicht übernommen.

Über Transaction.Current bekommst Du immer die Transaktion zurück, die gerade aktiv ist, oder null, wenn gerade keine Transaktion am aktuellen Thread hängt.

PS: Du kommst aber auch aus einer schönen Gegend

Das Auge ißt mit. 😉

18.02.2011 - 07:24 Uhr

Hallo spike24,

warum nimmst Du nicht einfach System.Transactions?


public void DoTransactionalWork()
{
    using(TransactionScope scope = new TransactionsScope(TransactionScopeOption.Required))
    {
        DoSomeSqlStuffA();
        DoSomeSqlStuffB();

        // Transaktionsbereich abschließen
        scope.Complete();
    }
}

Transaktionen sollten nicht innerhalb der Businessobjekte implementiert werden, da ein BusinessObject nicht sehr weit über seine eigene kleine Welt hinausblicken kann. Transaktionen fassen aber meist mehrere, ganz unterschiedliche Objekte zusammen. Teilweise ergibt sich erst zur Laufzeit aus der Aufrufkette, was zusammen in eine Transaktion muss.
System.Transactions hängt die Transaktionskennung intern an den aktuellen Thread. So können alle Methoden in der Aufrufkette ganz leicht an der Transaktion teilnehmen (wenn sie möchten).

16.02.2011 - 12:45 Uhr

Wobei ich gerade gelesen habe das ein Service Aufruf 100 bis 1000 mal langsamer ist als eine Methode (was auch klar ist) und das macht mir gerade Kopfzerbrechen...

Das stimmt so nicht ganz. Die Datenbankzugriffe (z.B. auf den SQL Server) gehen doch auch übers Netzwerk. Die sind genauso langsam. Wenn Du nun noch einen Applikationsserver dazwischen hast, wird es also nicht um Faktor 100 oder 1000 langsamer sondern eher um Faktor 1.1 bis 3 (je nach dem). Falls der Applikationsserver auch noch auf der selben Maschine wie die Datenbank läuft, ist es sogar möglicherweise überhaupt nicht "merklich" langsamer. Allerdings konkrrieren dann Datenbank und Applikationsserver um Rechnerresourcen.

denn dann weiß ich nicht ob dies für mich geeignet ist. Da ich bei jedem anklicken in einem DataGrid so einen Aufruf bräuchte... hmmm....

Von wie vielen geleichzeitigen Nutzern des Systems sprechen wir?

Man kann das auch so lösen, dass der Benutzer einen "Bearbeiten" Knopf klicken muss, um Daten ändern zu können. Dann kannst Du Rechteprüfung, Sperrprüfung und Sperrung an dieser Willenserklärung festmachen. Irgendwie musst Du den Zeitpunkt bestimmten, ab dem ein Benutzer z.B. einen Artikel bearbeitet. Das geht so am einfachsten.

16.02.2011 - 07:46 Uhr

Hallo Quaneu,

für gewöhnlich teilt man die Anwendung in zwei Prozesse (EXE-Dateien) auf. Ein Prozess für die Client-Anwendung mit Benutzeroberfläche. Davon startet jeder User seine eigene Instanz. Im Hintergrund läuft in einem zweiten Prozess die gemeinsame Geschäftslogik und Datenzugriffssteuerung. Den gemeinsamen Hintergundprozess nennt man Server-Prozess. Meistens werden solche Server-Prozesse als Windows-Dienst implementiert.

Damit die Konstruktion funktioniert, müssen Client-Prozesse mit dem Server-Prozess kommunizieren. Das geht z.B. übers Netzwerk mittels TCP/IP oder über Protokolle zur Interprozesskommunikation wie z.B. Named Pipes. Ob der Server-Prozess auf dem selben Computer wie der Client oder auf einem anderen Computer läuft ist für die Architektur zunächst nebensächlich.

Das .NET Framework enthält verschiedene Kommunikationstechnologien, um die Client/Server-Kommunikation abzuwickeln. Die populärsten dabei sind WCF, .NET Remoting und die Klassen zur Socketprogrammierung in System.Net.

Wenn Du weniger Zeit in die Implementierung der Kommunikation stecken und lieber mehr Zeit für die Umsetzung der fachlichen Anforderungen haben willst, kannst Du Dir auch mal das Kommunikation Framework Zyan ansehen. Zyan reduziert den Aufwand für die Client/Server-Kommunikation auf ein Minimum. Hier findest Du ein kleines Hello World-Beispiel mit Zyan: http://zyan.codeplex.com/wikipage?title=Erste%20Schritte&referringTitle=Deutsche%20Dokumentation.

14.02.2011 - 23:23 Uhr

Hallo malignate,

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.

10.02.2011 - 21:30 Uhr

Hallo malignate,

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:

IChannelReceiver:*object ChannelData {get;} *string[] GetUrlsForUri(string); *void StartListening(object); *void StopListening(object);

IChannelSender:*IMessageSink CreateMessageSink(string,object,out string)

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).

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?

10.02.2011 - 02:15 Uhr

Hallo malignate,

Wie siehts mit Request-Response Szenarien aus, zum Beispiel Callbacks für ein spezielles Request.

  
DoRequest(x =>   
   {  
      Console.WriteLine(x);  
   });  
  

Mit der neuen Zyan Version 1.2 funktioniert auch Dein Request-Response Szenario mit Callback.

08.02.2011 - 06:58 Uhr

Hallo zack0r,

Der Server-Prozess wird von einem dafür erzeugten Benutzer gestartet.

Und der Client? Der sollte auch unter einem AD-Benutzer laufen und nicht unter einem lokalen Benutzer.

Das Problem tritt nur auf, wenn der Server per Callback Daten an den Client zurücksenden soll.

Könnte auch ein Firewall-Problem sein. Probiers mal mit abgeschalteter Firewall auf dem Client.

Ich glaube allerdings, dass das Problem auch auftritt wenn ich den Projekt-Client unter einem anderen Benutzer, als den Server-Benutzer, direkt auf der Server-Maschine starte.

Ist der Serverbenutzer ein Domänenbenutzer oder ein lokaler Benutzer?

07.02.2011 - 09:06 Uhr

Hallo mikefried,

Du könntest die Binärdaten (byte[]) in einen Base64-String umwandeln und ganz einfach diesen codierten String versenden. Auf C# geht das so: MSDN: Convert.ToBase64String

In PHP kannst Du mit base64_decode die Daten wieder in die ursprüngliche Form bringen: http://stackoverflow.com/questions/888461/how-to-base64-decode-large-files-in-php

03.02.2011 - 01:07 Uhr

Hallo zack0r,

.NET Remoting verwendet standardmäßig Windows-Authentifizierung um die Kommunikation abzusichern. Das setzt vorraus, dass der Server die Identität der Client-Benutzers prüfen kann und umgekehrt. Dazu müssen Client- und Servercomputer Mitglied in der selben Active Directory-Domäne sein.

Falls Du kein Active Directory mit einem zentralen Domänenserver hast, musst Du sicherstellen, dass auf allen Computern im Peer-to-Peer Netzwerk identische Benutzerkonten mit identischen Passwörtern angelegt sind. Sonst klappt die Authentifizierung nicht. Ohne einen Domänenserver verwendet die Windows-Athentifizierung die lokale Benutzerdatenbank. Wenn Benutzer Bob nun auf dem Client-PC angelegt, aber auf dem Server-PC nicht (oder wenn Bob zwar angelegt ist, aber das Passwort nicht identisch ist), schlägt deshalb die Authentifizierung fehl.

Lösungsansätze:*Alle beteiligten Rechner der selben Active Directory-Domäne zufügen *Im Falle mehrerer Domänen, entsprechende Vertrauensstellungen einrichten *Im Falle von Peer-to-Peer identische Benutzerkonten an allen PCs einrichten *.NET Remoting Sicherheit per App.cofig oder programmatisch ausschalten

Wenn Du keine Domäne hast und die Authentifizierung gegen die lokale Benutzerdatenbank des Server oder gegen eine eigene SQL-Datenbank laufen lassen willst, kannst Du das mit Zyan machen. Zyan bringt mit dem TcpCustomServerProtocolSetup eine Konfigurationsmöglichkeit mit verschlüsselte Kommunikation ohne Domäne und ohne identische Benutzerkonten einzurichten.

Hier kannst Du das genauer nachlesen: http://zyan.codeplex.com/wikipage?title=Kommunikationsprotokolle%20konfigurieren&referringTitle=Deutsche%20Dokumentation

P.S. Zyan kann auch standardmäßig mit Events umgehen: http://zyan.codeplex.com/wikipage?title=Ereignisse%20verteilt%20einsetzen&referringTitle=Deutsche%20Dokumentation

27.01.2011 - 23:15 Uhr

Hallo malignate,

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 *Verteilte LINQ-Abfragen übers Netzwerk ermöglichen *Delegaten-Parameter erkennen und entsprechend verarbeiten

27.01.2011 - 01:31 Uhr

Ich habe eben die Zyan Version 1.1 veröffentlicht.
Die neue Version hat ein neues Feature, welches einen Post hier im Zyan-Projektthread auf mycsharp.de auf jeden Fall Wert ist:

Zyan unterstützt nun verteilte Events.

Und zwar ganz intuitiv, wie man es von button1_Click in Windows.Forms gewohnt ist. Hier ein kleines Beispiel, wie einfach man in einer verteilten Zyan-Anwendung mit Ereignissen arbeiten kann:

Server


public interface IMiniChat
{
    event Action<string,string> MessageReceived;

    void SendMessage(string nickname, string text);
}

public class MiniChat : IMiniChat
{
    public event Action<string, string> MessageReceived;

    public void SendMessage(string nickname, string text)
    {
        if (MessageReceived != null)
            MessageReceived(nickname, text);
    }
}

Client


private static string _nickName;

...

ZyanConnection connection = new ZyanConnection("tcp://localhost:9010/MiniChat");
IMiniChat chatProxy = connection.CreateProxy<IMiniChat>();

chatProxy.MessageReceived += new Action<string, string>(chatProxy_MessageReceived);

string text = string.Empty;

while (text.ToLower() != "quit")
{
    text = System.Console.ReadLine();
    chatProxy.SendMessage(_nickName, text);
}

...

private static void chatProxy_MessageReceived(string arg1, string arg2)
{
    if (arg1!=_nickName)
        System.Console.WriteLine(string.Format("{0}: {1}", arg1, arg2));
}

Einfacher geht´s wirklich nicht, oder?

Die komplette Beispiel-Projektmappe hängt als ZIP-Datei im Anhang.

26.01.2011 - 16:20 Uhr

... das Würde heißen, ich lege für jeden Mandanten die Struktur an und erzeuge alle DB Objekte(Tabellen Stored Procedures) mit einem Präfix z.B.: [Mandantenname]$[Objektname] und ich muss dann bei den Proc aufrufen nur noch den Präfix ranhängen. Da alle DB-Operationen über Stored Procedures ausgeführt werden muss ich ja nur beim Erzeugen dieser die Selects anpassen, was ja auch kein Problem ist. Ich werde das mal ins Auge fassen.

Kein Präfix vor die Tabellennamen machen!
Ich spreche von SQL Server Sechemas. So wie dbo.Tabelle (dbo ist das Standardschema des Database Owners) kannst Du auch eigene Schemas definieren, wie z.B. Mandant1.Angebote und Mandant2.Angebote. Auf Schemas kannst Du separat Zugriffsrechte vergeben.

Siehe Berechtigungshierarchie (Datenbankmodul)

Der SQL Server kann also Tabellen verschiedener Mandanten standardmäßig voneinander isolieren.

26.01.2011 - 08:11 Uhr

Von Sessions, jedweder Art, rate ich dringend ab. Falsch umgesetzt wird daraus schnell ein Strick.

Klar, man muss die Sitzungsverwaltung schon sauber implementieren. Vor allem sollte das Handling der Sitzungungen transparent und unter der Haube passieren. Dann kann auch nichts schief gehen.

Kommt der IIS zum Einsatz könnte für jeden Mandant ein Application Pool mit eigener Identität zum Einsatz kommen. Die Rechte könnten dann konsistent durchgezogen werden, so dass ein Client indirekt über die Services nur in die Datenbank schreiben könnte, die dem jeweiligen Mandant entspricht.

Ein Nachteil dieser Methode ist der erhöhte Deployment- und Konfigurationsaufwand. Es muss dann für jeden Mandant eine separate Kopie der Serveranwendung ausgerollt und gepflegt werden. Außerdem ist jede Mandanteninstanz dann über einen anderen URL / Port erreichbar. Das muss ich im Client wieder in der Konfiguration verwalten.

Ein weiterer Vorteil ist die Isolation der einzelnen Mandanten im Hosting-Prozess.

Dazu muss man nicht für jeden Mandanten eine eigene Kopie der Serveranwendung hosten. Eigentlich ist es sogar einfacher, alle Mandanten in einer SQL Server Datenbank zu verwalten. Für jeden Mandant wird ein Schema erstellt. Für jeden Mandanten wird ein separates SQL Login erstellt, welches nur Zugriffsrechte auf die Tabellen im Schema des entsprechenden Mandanten hat. Für Stammdaten, die mandantenübergreifend genutzt werden (Devisenkurse, Postleizahlen, Ländertabellen etc.) gibt es ein Stammdatenschema, auf das alle Mandanten SQL Logins Zugriff haben. Das hällt die SQL Datenbank schlank, isoliert die Mandantendaten aber trotzdem sicherheitstechnisch hervorragend.

So brauche ich weder verschiedene Connection Strings, noch mehrfaches Ausrollen der Lösung. Der Client muss nur beim Anmeldevorgang am Applikationsserver angeben, für welchen Mandanten er sich anmeldet. Damit er das nicht bei jeder entfernten Methode als Parameter mitgeben muss, braucht es eine Sitzungsverwaltung.

Es sollte vermieden werden, alles das was eigentlich in einer Sitzung gehalten werden sollte (Benutzeridentität, Mandantenschlüssel, usw.) bei jedem entfernten Methodenaufruf in Headern zwischen Client und Server ausgetauscht wird. Das ist unnötiger Overhead, der sich Nachteilig auf die Performanz auswirkt. Ein eindeutiger Sitzungsschlüssel (vorzeugsweise eine Guid, da man die nicht erraten kann) genügt.

Der Knackpunkt ist, wie dieser Sitzungsschlüssel - ohne viel Aufsehen und ohne ihn immer irgendwie in die Hand nehmen zu müssen - vom Client zum Server (und von dort ggf. auf weitere Server) gelangt. In .NET Remoting ist das kinderlicht. Da gibt es den sogenannten Aufrufkontext (CallContext). Dort packt man den Schlüssel auf der Clientseite rein und er wird automatisch über die gesamte Aufrufkette an alle Kommunikationsteilnehmer implizit übertragen. Auf dem Server kann man den Schlüssel einfach wieder aus dem CallContext rausholen.
In WCF gibt es keinen CallContext. Man muss sich sowas also selber bauen. Also eine WCF-Erweiterung, die den aktuellen Sitzungsschlüssel am Client aus einer statischen (oder threadstatischen) Variable liest und ihn als Transportheader an die zu versendende WCF-Nachricht anhängt. Serverseitig wird ebenfalls eine Erweiterung benötigt, die vor dem Dispatchen der Nachricht den Sitzungsschlüssel aus dem entsprechenden Header liest und in einer threadstatischen Variable (oder in einem Slot des Threadspeichers; ist aber langsamer als eine threadstatische Variable) ablegt. Der Dienstaufruf kann den Sitzungsschlüssel des Aufrufers dann einfach jederzeit aus der threadstatischen Variable lesen. Da jeder Dienstaufruf in einem eigenen Thread abgearbeitet wird, gibt es auch keine Probleme wenn Benutzer A die Dienstmethode GetInvoice für Mandant 1 und Benutzer B für Mandant 2 aufruft. Die Sitzung und damit die Mandanteninformation wird von der Kommunikationsinfrastruktur an den jeweiligen Arbeitsthread "gehängt".

Mit diesem Ansatz habe ich sehr gute Erfahrungen gemacht.

Natürlich kann man Mandanten auch über getrenntes Hosting und getrennte Datenbanken abbilden. Das ist ja nicht falsch und die naheliegendste Lösung. Erfahrungsgemäß verursacht dies aber höhere Betriebskosten.

25.01.2011 - 09:23 Uhr

Hallo Campy,

Als "Sessionprovider" verwende ich wohl am besten gleich die Datenbank oder?

Das kommt auf die vorraussichtliche Größe Deines Projekts an. Wenn die Software für nur wenige (1-50) gleichzeitige Benutzer ausgelegt werden muss/soll und der Betrieb des Applikationsservers in einem Cluster nicht in Frage kommt, bist Du mit einem In-Memory-Sessionprovider schneller und unkomplizierter unterwegs.

Für alle anderen Anwendungsfälle unbedingt die Sitzungen in einer DB (z.B. SQL Server) verwalten. Das macht die Anwendung wesentlich skalierbarer und versperrt auch nicht den Weg für einen Einsatz im Cluster. Wenn Datenbankserver und SQL Server im selben Backbone-Netz sind, werden die kurzen Zugriffe auf die Sitzungstabellen verschmerzbar sein.

Im Zweifelsfall größer Denken, denn wer weiß, wie viele User die Anwendung in fünf Jahren bedienen muss.

25.01.2011 - 07:54 Uhr

Hallo Campy,

was Du brauchst ist eine Sitzungsverwaltung. Wenn ein Client sich erfolgreich angemeldet hat, sollte auf dem Server eine Sitzung erzeugt werden, welche die Identität des Client-Benutzers und seine Sitzungseinstellungen (z.B. an welchem Mandanten angemeldet) speichert. Du brauchst den Client dann nicht jedes Mal zu authentifizieren und die Einstellungen für jeden Funktionsaufruf mitgeben.

Leider kann WCF das standardmäßig nicht. Unter Sitzung wird in WCF was anderes verstanden. Man kann das zwar selber in WCF nachrüsten. Dazu muss man sich aber intensiv mit den Eingeweiden von WCF auseinandersetzen und eine eigene Erweiterung (Behavor) schreiben. Wenn Dein Szenario nicht zu komplex ist, kannst Du die Sitzungsgeschichte über den OperationContext abbilden. Glücklich wirst Du aber auf lange Sicht damit nicht werden.

Interessanter sind da schon folgende Links:
MSDN: WCF Extensible Objects
MSDN: Configuring and Extending WCF with Behaviors

Wenn es nicht unbedingt WCF sein muss und Deine Anwendung auch nicht interoperabel sein muss, dann könnte Zyan für Dich interessant sein. Zyan bringt eine fertige Sitzungsverwaltung inklusive Unterstützung für Sitzungsvariablen mit. Hier findest Du ein Kleines Anwendungsbeispiel für Zyan: Zyan Dokumentation: Erste Schritte

24.01.2011 - 08:51 Uhr

Hallo xheinrich,

das passt so wirklich nicht. .NET ist keine Technologie für verteilte Anwendungen. Es ist viel mehr als das. Auch für Java Enterprise Edition stimmt das nicht. Bei Java fallen mir z.B. folgende Kommunikationstechnologieen (bin kein Java-Experte) ein:*Java RMI (Remote Method Invocation) *Diverse SOAP Webservice Implementierungen (AXIS, Glassfish) *JMS (Java Messaging Service)

Ähnlich sieht es bei .NET aus:*.NET Remoting (ähnlich wie JRM) *ASP.NET Webdienste *Windows Communication Foundation *Enterprise Services (COM+ für .NET)

Deine Tabelle vergleicht Äpfel mit Birnen. Du vermengst folgende Themen:*Standards und Protokolle (SOAP, CORBA, DCOM, XML-RPC) *Plattformen (.NET, JEE, COM+) *Dinge die nichts mit verteilten Systemen zu tun haben (z.B. ADO.NET, JDBC)

CORBA ist ein Standard und keine konkrete Implementierung. Du kannst also CORBA nicht mit .NET vergleichen. Du kannst CORBA vielleicht mit SOAP vergleichen oder du könntest verschiedene CORBA-Implementierungen vergleichen die auf verschiedenen Plattformen aufsetzen. Eine CORBA-Implementierung für .NET wäre z.B. IIOP.NET, welche auf der Kommunikationstechnologie .NET Remoting aufbaut, die Teil des .NET Framework ist.
Zwei CORBA-Implementierungen sind nicht automatisch miteinander verträglich, weil der CORBA-Standard viel Raum für Sonderlösungen lässt.

Du könntest auch Webservice-Implementierungen vergleichen. Allein innerhalb der .NET Welt gibt es davon schon drei Stück:*ASP.NET Webdienste *Windows Communication Foundation (BasicHttpBinding, WsHttpBinding) *.NET Remoting (HttpChannel + SoapFormatter)

Was Dinge wie Datenrepräsentation angeht, kannst Du bei .NET auch nicht einfach ADO.NET angeben. Wie die Daten übers Netzwerk gehen, hängt von der einggesetzten Technologie und deren Konfiguration ab:*.NET Remoting HttpChannel + SoapFormatter: Übertragung in XML-Form *.NET Remoting TCPChannel + BinaryFormatter: Binäre Datenübertragung *WCF BasicHttpBinding: Übertragung in XML-Form *WCF WsHttpBinding: Übertragung in XML-Form *WCF NetTcpBinding: Binäre Datenübertragung *Enterprise Services/DCOM/COM+: Binäre Datenübertragung

.NET als eine einzige Spalte in Deiner Tabelle abzubiden wäre also schlichtweg falsch.

Du solltest vielleicht mehrere Tabellen machen, um dem Leser Stück für Stück einen Überblick über die Welt der verteilten Systeme und ihrer Standards, Protokolle und Technologieen zu geben. Eventuell ist es ja auch interessant, für welche Standards/Protokolle es für welche Plattform Implementierungen gibt, wie gebräuchlich diese auf der jeweiligen Plattform sind und inwieweit Interoperabilität mit anderen Plattformen möglich ist.

Besonders der Punkt Komponententechnologieen ist schwer vergleichbar. Du hast bei .NET die Enterprise Services aufgeführt. Diese sind aber inzwischen obsolet. Niemand entwickelt neue Anwendungen mehr auf Enterprise Services. Schon seit .NET 2.0 (Jahr 2005) hat das eigentlich niemand mehr getan. Der Punkt ist, dass die gebräuchlichen Komponententechnologieen in Java einen ganz anderen Ansatz haben, als es bei .NET der Fall ist. Der Java-Welt entscheidet man sich für einen Applikationsserver (IBM Webshpere, JBoss, BEA Weblogic, Glassfish) und baut seine Komponenten auf dessen Modell auf (z.B. Enterprise Java Beans). Das Komponentenmodell macht strikte vorgaben, wie Komponenten zu entwerfen sind. Es müssen z.B. bestimmte Schnittstellen implementiert werden, damit der Betrieb in der Komponenten-Infrastruktur gelingt und die angebotenen Zusatzdienste (Persistent, Caching, Transaktionen, Sicherheit, etc.) nutzbar sind.
Bei .NET ist das anders. Da gibt es keine vorgefertigte Komponenten-Infrastruktur in der Form. Es gibt vielmehr verschiedene Technoilogieen welche die einzelenen Themengebiete abdecken (z.B. ADO.NET oder Linq2SQL für Persistent, .NET Remoting oder WCF für Kommunikation). Diese lassen sich völlig frei kombinieren. Es gibt auch keinen vorgefertigten Applikationsserver, wie es bei Java der Fall ist. Man kann verteilte .NET Komponenten fast überall hosten (Konsolenanwendung, Windows-Anwendung, Windows-Dienst, IIS, Office Add-In, selbstgebaute Applikationsserver).
Bei Enterprise Services war es noch am ehesten so, wie in der Java-Welt. Aber das ist heute Schnee von gestern.

Was möchtest Du genau herausarbeiten?
Was möchtest Du dem der Leser Deiner Studienarbeit vermitteln?

Ich helfe gerne weiter.

24.01.2011 - 07:18 Uhr

Hallo alexc3,

Was hast du eigentlich für Erfahrungen mit Stored-Procedures gemacht?
Hab mal irgendwo aufgeschnappt man könnte ja auch temporäre Tabellen in Stored Procedures verwenden und dann dort quasi ein Mapping vornehmen.

Mit Stored Procedures kannst Du auch mappen. Für SELECT-Abfragen klappt das ganz gut. Aber wie sieht es mit INSERT, UPDATE, DELETE aus? Schlecht. Im Idealfall sollte das Mapping so transparent sein, dass an der alten Anwendung nichts geändert werden muss. Das geht eigentlich nur, indem die alten Tabellen so bleiben wie sie sind und mittels Trigger auf die entsprechenden neuen Tabellen gemappt werden. Umgekehrt sorgen Trigger auf den neuen Tabellen dafür, dass Änderungen auf die alten Tabellen gemappt werden. Die Schwierigkeit dabei sind Details. Angenommen Du hast in alten oder neuen Tabellen Spalten mit Auto-Increment, dann musst Du sicher stellen, dass diese Identisch vergeben werden. Falls das nicht möglich ist, musst Du Zuordnungstabellen anlegen, die alte Schlüssel in neue Schlüssel und umgekehrt auflösen können.

Du könntest auch etwas ganz anderes machen. Statt das Mapping im SQL Server zu implementieren, könntest Du es in der Datenzugriffsschicht Deiner neuen Anwendung ansiedeln. Du hättest dann eine Datenzugriffsschicht für die alte Tabellenstruktur und eine für die neue Tabellenstruktur. Die Datenzugriffsschicht mappt die Daten dann auf eine neutrale Datenstruktur mit der die Anwendung intern arbeitet. Wenn die Migration aller Modul abgeschlossen ist, kannst Du die Datenzugriffsschicht einfach austauschen.

Welche Methode in Deinem Fall besser geeignet ist, kann ich nur schwer sagen, da ich das Projekt natürlich nicht kenne.

21.01.2011 - 08:09 Uhr

Hallo alexc3,

... hier habe ich jedoch eine sehr unsaubere Datenbankstruktur in der nichtmal die Tabellen- oder Spaltennamen einem einheitlichen Namens-Schema folgen, von (wirklich) unsinnigerweise redundanten Daten ganz zu schweigen.

Dann ist allerdings wirklich eine Überarbeitung der Datenbankstruktur nötig.

Da die Module immer verschiedene Abteilungen betreffen, werden so also Schrittweise einzelne Abteilungen umgestellt werden (z.B. Verkauf), daher "klickt" eine Abteilung ansich nur noch in einer Anwendung (entweder neue oder alte) herum und muss nicht ständig zwischen Access und C# wechseln.

Mit Stammdaten allein werden allerdings die wenigsten Abteilungen auskommen. Es gibt eine ganz einfach Möglichkeit, von Access-Formularen aus auf C#-Formulare zu navigieren oder umgekehrt. Und zwar über Hyperlinks. Angenommen Du möchtest den Artikel 4711 einer Angebotsposition (im Access-Formular) im Artikelstamm (C#-Formular) öffnen. Dann möchtest Du vermutlich nicht Tonnenweise COM-Interop-Code schreiben. Du kannst in Access einfach folgendes tun:

FollowHyperlink "erp://ShowArticleMaster/4711"

Damit dieser Link funktioniert, benötigst Du nur eine kleine Konsolenanwendung, die von Windows gestartet wird, wenn jemand einen "erp://" Link aufruft und den Hyperlink-String als Parameter übergibt. Diese Konsolenanwendung muss dann nur einmalig in der Registry für das erp-URL-Protokoll registiert werden. Wie das geht, findest Du hier: http://dotnet-snippets.de/dns/eigenes-url-protokoll-registrieren-SID253.aspx

Auch in C# ist das ganz einfach nutzbar.


System.Diagnostics.Process.Start(@"erp://ShowSalesOffer/12345");

Die Konsolenanwendung bekommt von Windows den kompletten Hyperlink-String, der aufgerufen wurde, als Kommandozeilenparameter (args[] in main-Funktion) übergeben. Du brauchst den String also nur zerlegen und auswerten. Access steuerst Du über COM-Interop und C# über Remoting mit IpcChannel oder Zyan mit IPC Protokolleinstellung.

Diese erp-Hyperlinks lassen sich auch in Webseiten (z.B. Intranet), E-Mails, Word-, Excel- oder PDF-Dokumenten verwenden. So kann Sachbearbeiter A schnell eine E-Mail zu Sachbearbeiter B mit einem Link zum Kunden X mit der Bitte senden, diesen zurückzurufen. Mit einem Klick hat Sachbearbeiter B den richtigen Kunden geöffnet. Kein Suchen mehr.

Ob das zu öffnende Formular über Access oder die C#-Anwendung geöffnet wird, kann in der Konsolenanwendung entschieden werden. Theoretisch kannst Du die Aufrufkonfiguration für diese erp-Hyperlinks auch in der DB ablegen. Dann kannst Du die zu verwendende Version einfach zentral für bestimmte Abteilungen/Benutzer umschalten.

aus Sicht der Access-Anwendung darf sich die Datenbank nicht verändern, aber die alte Datenbank hat leider eine sehr schlechte Struktur, sodass die Datenbank neu designed werden muss.

Die Datenbank ist das Fundament einer Geschäftsanwendung. Wie die Murks ist, wird auch die neue C#-Anwendung Murks werden, wenn sie darauf aufbaut.

Du könntest aber z.B. neue Tabellenstrukturen parallel anlegen und diese mit den Alten über Trigger synchronisieren. Das klappt sehr zuverlässig. Für Fällen in denen die Struktur okay ist, aber die Benennung der Horror ist, kannst Du auf dem SQL Server Views erzeugen, welche die neuen Tabellen über alte Namen zugreifbar machen. Diese Views heißen dann wie die alten Tabellen und die entsprechenden alten Tabellen werden gelöscht.

Oder ist die DB keine SQL Server-DB sondern Access MDB/ACCDB?

Meinst du mit COM-Interop wirklich das "Fernsteuern" der Access-Anwendung aus meiner C#-Anwendung heraus oder habe ich dich falsch verstanden?

Ja, fernsteuern. Das hast Du schon richtig verstanden. Du sollst den Fernsteuerungscode aber nicht direkt in Deine C#-Anwendung einbauen. Sonst haben Deine neuen C#-Module Abhängigkeiten zu dem alten Access-Gerümpel.

20.01.2011 - 07:08 Uhr

Hallo punkdevil,

vielleicht prüft der SAP Webservice die Identität des Aufrufers gegen eine Datenbank (z.B. Active Directory, LDAP, ezc.). Das Systemkonto ist ein vordefiniertes lokales Windows-Konto und wird in der Datenbank nicht vorhanden sein. Die 15 Sekunden sucht er vielleicht in so einer Datenbank nach dem Benutzer und findet ihn nicht, führt die Anfrage ab am Ende trotzdem aus, da für diese Aufgabe keinee Authorisierung notwendig ist.

Du solltest eigene Dienst wenn möglich immer unter einem Domänenkonto laufen lassen. Nur so kannst Du die Rechte konfigurieren, die das Diestkonto erhalten soll. Außerdem können Domänenkonten leichter für die Authentifizierung in anderen Anwendungen herangezogen werden.