myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
» Regeln
» Wie poste ich richtig?
» Forum-FAQ

Mitglieder
» Liste / Suche
» Wer ist wo online?

Ressourcen
» openbook: Visual C#
» openbook: OO
» Microsoft Docs

Team
» Kontakt
» Übersicht
» Wir über uns
» Datenschutzerklärung
» Impressum

» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Entwicklung » Netzwerktechnologien » Design einer Remoting-Anwendung
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

Design einer Remoting-Anwendung

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
Daedalus Daedalus ist männlich
myCSharp.de-Mitglied

Dabei seit: 30.05.2006
Beiträge: 8
Entwicklungsumgebung: Visual Studio .NET
Herkunft: Deutschland


Daedalus ist offline

Design einer Remoting-Anwendung

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Moin zusammen!

Ich habe da mal eine Frage zum grundlegenden Design einer Remoting-Anwendung.

Ich versuche mich an einer Client-/Server-Anwendung, die bislang grob den folgenden Aufbau hat:
  • Klasse formClient: GUI des Clients (behandelt z.B. die Eingaben des Benutzers und übergibt diese der Klasse Client)
  • Klasse formServer: GUI des Servers (verschiedene Server-Einstellungen wie z.B. Portnr. etc.)
  • Klasse Client: Logik des Clients ("schickt" u.a. die Eingaben an den Server)
  • Klasse Server: Logik des Servers (Erstellen des TCPChannels etc.)
  • Klassen mit Geschäftslogik (verschiedene Berechnungen)
  • Interface IServer
Der Server soll dem Client nun die Funktionen aus den Geschäftslogik-Klassen zur Verfügung stellen. Dazu habe ich nun einige Tutorials, Hilfen etc. gelesen (z.B. auch  in diesem Forum) in denen empfohlen wird, auf Client-Seite nur mit Interfaces zu arbeiten, damit bei internen Änderungen auf der Server-Seite der Client nicht upgedatet werden muss.

Meine Frage ist nun, wie ich das bei mehreren Geschäftslogik-Klassen realisieren sollte. Wenn ich nun z.B. die Klasse Berechnung habe, deren Methode BerechneEtwas() ich dem Client zur Verfügung stellen will, wie würde man das am "saubersten" implementieren?
  • Nur den Server marshallen und hier eine Methode BerechneEtwas() anlegen, die einfach nur die Methode in Klasse Berechnung aufruft und deren Ergebnis zurückgibt. Diese müsste dann auch im Interface IServer angelegt werden. Das hätte zur Folge, dass in der Klasse Server hauptsächlich Methoden enthalten wären, die semantisch hier gar nicht hingehören.
  • Nur den Server marshallen und für jede gwünschte Klasse eine Methode anlegen, die ein Objekt dieser Klasse zurückgibt, mit dem der Client weiterarbeiten kann. Dazu muss jede Klasse serialisierbar und dem Client über ein Interface bekannt sein.
  • Jede Geschäftslogik-Klasse einzeln marshallen und entsprechend mehrere Interfaces bereitstellen. Hierzu bräuchte man (meines Wissens nach) mehrere Channel, was ich eigentlich nicht will.
Des Weiteren habe ich noch eine Frage zum Aufruf der Methoden in den Formularen. Wenn ich nun bspw. nach dem Klicken auf einen Button im Client-Formular dessen Daten an den Server zum Verarbeiten senden will, habe ich in Klasse formClient folgende zwei Möglichkeiten:
  • Im Formular formClient referenziere ich ein Client-Objekt, das wiederum ein Server-Objekt referenziert, und rufe dessen Methode mit den Parametern auf: this.client.server.TuWas(Parameter). Dabei greife ich auf das Attribut server zu, was nicht so sauberer Stil ist.
  • Im Formular formClient rufe ich die Methode TuWas(Parameter) des Cliens auf. Diese Methode ruft die Methode TuWas(Parameter) des Servers auf. Hierbei entsteht eine Verkettung von Methodenaufrufen, was ich auch irgendwie sehr komisch finde.
Bei beiden Fällen wäre dann noch zu klären, ob letztlich überhaupt der Server die Methode TuWas() anbietet oder diese an die Geschäftslogik weiterreicht (siehe erste Frage).

Ich hoffe, ich konnte mein Problem einigermaßen verständlich machen. Das Remoting an sich (per TCPChannel etc.) klappt einwandfrei, aber die logische und semantisch korrekte Abbildung der Methoden in den entsprechenden Klassen ist im Moment mein Hauptproblem. Ich hätte gerne einen schönen, sauberen Code smile

Oh, und wenn noch Zeit ist: Ist es möglich, Formulare auf dem Server zu implementieren, die dann auf dem Client angezeigt werden? Also quasi ein Marshaling von Formularen, die auf dem Server geändert werden können, aber auf dem Client (z.B. mit Hilfe von Interfaces) nur angezeigt werden, ohne dass dieser den Code kennen muss. Ich denke da an einen Client, der nur einige Menüeinträge umfasst, beim Klick auf diese die entsprechenden Formulare jedoch vom Server lädt und anzeigt.

Danke schonmal im Voraus an alle, die sich hierfür Zeit nehmen! smile

Gruß
Daedalus
30.05.2006 16:22 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Rainbird Rainbird ist männlich
myCSharp.de-Poweruser/ Experte

avatar-2834.jpg


Dabei seit: 28.05.2005
Beiträge: 3.721
Entwicklungsumgebung: Visual Studio 2012
Herkunft: Mauer


Rainbird ist offline

Aufbau

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Ich verstehe nicht was Du mit "den Server marshallen" meinst. Eine Remoting-Anwendung bestht aus folgenden Teilen:
  • Host (das meinst Du warscheinlich mit Server)
  • Vom Host gehostete Geschäftslogik, die Clients angeboten wird
  • Schnittstellen zu den angebotenen Geschäftsklassen in separaten Assemblies
  • Client (Irgendein Stück Software, welches die Geschäftslogik auf dem Remoting Host nutzt)
Der Host tut außer dem veröffentlichen der Klassen eigentlich nix. Man braucht ihn aber als Lebensraum-Prozess für die Objekte, die per RPC erzeugt werden.

In den meisten Fällen werden die Geschäftslogik-Klassen (also die Typen, keine Instanzen) serveraktiviert als SingleCall oder Singleton (Ja nach Einsatz) veröffentlicht. Jede Klasse hat ihre eigene Schnittstelle. Das geht alles mit einem Channel. Über den Channel gehen Clientanfragen beim Host ein. Für jede Anfrage wird ein neuer Thread erzeugt, der die remote aufgerufene Funktion abarbeitet. Bei SingleCall Aktivierung wird eine Instanz der angefragten Klasse erzeugt, die Funktion ausgeführt und die Instanz anschließend sofort wieder entsorgt. Bei Singeton verwenden alle Clientanfragen eine einzige Instanz. Diese wird bei der ersten Clientanfrage erzeugt. Bei verwendung der Singleton Aktivierung sollte man unbedingt threadsicher programmieren.

Alternativ gibt es auch die Möglichkeit, dass der Host Instanzen von Geschäftslogik-Klassen erzeugt und diese direkt veröffentlicht. Dazu ist allerdings etwas Handarbeit nötig. Wird aber meistens nicht benötigt (Meinst Du vielleicht das, mit "den Server marshallen"?).

Einige Sachen sind in Deinem Beispiel nicht schlüssig, weil Du alles Client oder Server nennst. Da gibts das frmClient und die Client-Klasse, usw.. In einem realen Projekt würden die Klassen niemals so heißen. Wenn die Client-Klasse nur Funktionsaufrufe 1:1 an den Remoting-Host weiterleitet, ist sie unnötig. Dann kannst Du das Zeug auch direkt aufrufen. Mehr Sinn macht eine Strukturierung des Client-Code im Sinne des MVC Pattern (Dazu findest Du hier im Forum einiges). Sinnvoll wäre die Client-Klasse auch wieder im Sinne einer Factory, die sich zentral um das erzeugen der Proxies und das casten in die benötigten Interfaces kümmern. Außerdem ist so eine Factory auch gut geeigent, um die Verarbeitung von Konfigurationseinstellungen aus dem Formular-Code heraus zu halten. Bei Remoting fällt mindestens eine Konfig-Einstellung an: Der URL zum Remoting-Host.

Formulare auf dem Server ergeben keinen Sinn, da man sie auf dem Client nicht sehen würde. Die Formulare würden letztendlich im Grafikspeicher des Servers landen. Versteuerungen von Formularen auf einem Server ist auch keine gute Architektur für robuste verteilte Anwendungen. Du kannst natürlich eine Komponente auf dem Remoting Host veröffentlichen, die dem Client konfigurierbare Menüeinträge (z.B. aus einer Datenbank) oder ähnliches anbietet. Das wird gerne gemacht, wenn Anwendungen zentral für mehrere Benutzer angepast oder erweitert werden sollen. Der Client könnte sogar automatisch PlugIns nachlagen etc.
31.05.2006 07:55 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
naumann naumann ist männlich
myCSharp.de-Mitglied

Dabei seit: 17.10.2005
Beiträge: 61
Entwicklungsumgebung: VS 2003 Enterprise Architect


naumann ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hast du dir schonmal das Lernvideo von MSDN angesehen?
Da wird alles erklärt, wenn man noch nichts von .Net Remoting weiß.

 Hier isses nochmal.
31.05.2006 10:08 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Daedalus Daedalus ist männlich
myCSharp.de-Mitglied

Dabei seit: 30.05.2006
Beiträge: 8
Entwicklungsumgebung: Visual Studio .NET
Herkunft: Deutschland

Themenstarter Thema begonnen von Daedalus

Daedalus ist offline

Diagramm

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Moin!

Erstmal danke für die umfangreiche Antwort.

Zu meiner zweiten Frage: Das habe ich mir schon fast gedacht. Bei meinen Versuchen war es nämlich genau so: Die Formulare wurden auf dem Host angezeigt... naja, egal smile

Zur ersten Frage: Ich habe mich wohl ein wenig umständlich ausgedrückt. Im Prinzip kann man in den Ausführungen "Server" durch "Host" ersetzen smile

Ich habe mal zur besseren Anschaulichkeit ein kleines Diagramm meiner Anwendung angefügt:


Ablauf der Kommunikation:
  • Anwender klickt Button "Verbinden" in formClient
  • formClient.btnVerbindeClick wird ausgeführt
  • formClient.client wird als Client instantiiert und verbindeMitServer aufgerufen. Hier wird nun der Channel aufgebaut und das Host-Objekt instantiiert, das über formClient.client.host angesprochen werden kann.
  • Das erfolgreiche Aufbauen der Verbindung wird über TesteVerbindung
    geprüft, und das funktioniert auch.
Ausschnitt aus "Client.cs": VerbindeMitServer um die Verbindung aufzubauen:

C#-Code:
this.chan = new TcpChannel(0);
ChannelServices.RegisterChannel(this.chan);
object obj = RemotingServices.Connect(typeof(IHost), "tcp://adresse");
this.host = obj as IHost;
this.IstVerbunden = this.host.TesteVerbindung();

Wie stelle ich dem Client aber nun die Methoden BerechneWas1 zur Verfügung, wenn der Anwender auf den Button "BerechneWas1" klickt? Also wie "verknüpfe" ich die Interfaces auf dem Client mit den tatsächlichen Objekten auf dem Host?

Ich habe doch auch dem Client nur Zugriff auf das Host-Objekt!? Muss ich also...
  • ... das Host-Interface und auch die entsprechende Klasse mit Methoden versehen wie BerechneWas1, die dann die entsprechenden Methoden in den anderen Klassen aufrufen und deren Ergebnisse zurückgeben?
  • ... komplette Objekte übergeben, z.B. mit einer Methode GetBerechnung1 auf dem Host?
Im ersten Fall sähe meine Methode btnBerechneWas1Click in formClient vereinfacht wie folgt aus:

C#-Code:
double ergebnis = this.client.host.BerechneWas1();

Und das finde ich seltsam wegen dem Zugriff auf client.host und auch, weil die Interfaces für die Berechnungsklassen eigentlich überflüssig wären.

Beim zweiten Ansatz bekomme ich Probleme beim "Übergeben" der Objekte, wie du auch schon gesagt hast.

Also irgendwie habe ich das Ganze wohl noch nicht so richtig verstanden... smile

Das mit dem Lernvideo habe ich gerade erst gesehen. Schaue ich mir mal eben an...

Grüße
Deadalus
31.05.2006 10:26 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Daedalus Daedalus ist männlich
myCSharp.de-Mitglied

Dabei seit: 30.05.2006
Beiträge: 8
Entwicklungsumgebung: Visual Studio .NET
Herkunft: Deutschland

Themenstarter Thema begonnen von Daedalus

Daedalus ist offline

Idee

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Mhhh... die Seite mit dem Video kannte ich schon, aber beim zweiten Lesen ist mir dann doch vielleicht die Lösung aufgefallen Augenzwinkern

Muss ich die Sache vielleicht wie folgt lösen?

Ausschnitt aus "Client.cs":

C#-Code:
this.chan = new TcpChannel(0);
ChannelServices.RegisterChannel(this.chan);

object host = RemotingServices.Connect(typeof(IHost), "tcp://adresse/Host");
this.host = obj as IHost;
this.IstVerbunden = this.host.TesteVerbindung();

object berechnung1 = RemotingServices.Connect(typeof(IBerechnung1), "tcp://adresse/Berechnung1");
this.berechnung1 = obj as IBerechnung1;

Dann hätte ich einfach mehrere Remote-Objekte lokal verfügbar und könnte sie über die Interfaces ansprechen.

Hatte ich die ganze Zeit über ein (nicht gerade kleines) Brett vor'm Kopf und es ist tatsächlich so einfach? smile

Grüße
Daedalus
31.05.2006 10:32 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Rainbird Rainbird ist männlich
myCSharp.de-Poweruser/ Experte

avatar-2834.jpg


Dabei seit: 28.05.2005
Beiträge: 3.721
Entwicklungsumgebung: Visual Studio 2012
Herkunft: Mauer


Rainbird ist offline

Ich kenn das anders

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Um ein vom Host angebotenes Objekt als Proxy auf dem Client zu bekommen, gehe ich normal so vor:

C#-Code:
IDemo obj=(IDemo)Activator.GetObject(typeof(IDemo),"tcp://host:12345/AppName/ClassName");
01.06.2006 07:49 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Daedalus Daedalus ist männlich
myCSharp.de-Mitglied

Dabei seit: 30.05.2006
Beiträge: 8
Entwicklungsumgebung: Visual Studio .NET
Herkunft: Deutschland

Themenstarter Thema begonnen von Daedalus

Daedalus ist offline

Andere Möglichkeit

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Ja, deine Methode habe ich auch in den meisten Beispielen gesehen und verwende sie jetzt auch selbst. "Meine" Methode habe ich aus dem Buch von O'Reilly: " Programmieren mit C#".

Gruß
Daedalus
01.06.2006 21:29 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum Der Startbeitrag ist älter als 12 Jahre.
Der letzte Beitrag ist älter als 12 Jahre.
Antwort erstellen


© Copyright 2003-2019 myCSharp.de-Team | Alle Rechte vorbehalten. | Dieses Portal verwendet zum korrekten Betrieb Cookies. 22.05.2019 04:37