Tutorial: Einen DataSnap-Server mit einer Anwendung verwenden

Aus RAD Studio
Wechseln zu: Navigation, Suche

Nach oben zu Tutorials zu Datenbanken und LiveBindings


Die DataSnap-Technologie ermöglicht, Client-Serveranwendungen zu erstellen, die über das Internet, das lokale Netzwerk oder den lokalen Host kommunizieren.

Das folgende Beispiel demonstriert die Verwendung von DataSnap beim Erstellen einer einfachen lokalen Client-Serveranwendung. Die Client- und die Serveranwendungen sind in Delphi implementiert. Nach dem Erstellen des Servers und der Aktivierung der Verbindung zwischen dem Client und dem Server mit DataSnap, kann der Client Methoden aufrufen, die auf dem Server definiert und implementiert sind.

Sie können einen Server entweder in Delphi oder C++ implementieren. Dieses Beispiel zeigt beides. Der Client muss nicht in derselben Sprache implementiert werden. Sie können z.B. einen Delphi-Server und einen C++-Client — oder umgekehrt — verwenden.

DataSnap-Serverkomponenten

Die Hauptkomponenten sind:

Die Komponente TDSServer ist das logische Zentrum der DataSnap-Serveranwendung. Sie enthält die Methoden Start und Stop zum Starten und Stoppen des Servers und außerdem die Eigenschaft AutoStart. Standardmäßig ist der Wert der Eigenschaft AutoStart auf True gesetzt, so dass der Server beim Anwendungsstart automatisch startet. Sie benötigen nur eine TDSServer-Komponente pro Serveranwendung.

Die Komponente TDSServerClass repräsentiert eine Serverklasse.

Der DataSnap-Server erstellt automatisch Instanzen der Serverklassen und gibt diese auch automatisch frei. Die Instantiierung einer Serverklasse wird von der Eigenschaft LifeCycle der Komponente TDSServerClass gesteuert. Die Eigenschaft LifeCycle hat drei mögliche Werte: Server, Session und Invocation.

  • Wenn LifeCycle auf Server gesetzt ist, erstellt der DataSnap-Server eine Instanz einer Serverklasse, die von allen mit der Serveranwendung verbundenen Clients verwendet wird. Dies repräsentiert ein “Singleton”-Muster. Gehen Sie bei der Verwendung der Server-Lebensdauer mit Sorgfalt vor, weil Ihre Serverklassenimplementierung Thread-sicher sein muss: Sie müssen die Serverklasse so erstellen, dass auf sie gleichzeitig von mehreren Threads zugegriffen werden kann.
  • Der Vorgabewert für LifeCycle ist Session. Das bedeutet, dass der DataSnap-Server eine Instanz einer Serverklasse für jeden verbundenen Client erstellt.
  • Der dritte mögliche Wert für die Eigenschaft LifeCycle ist Invocation. In diesem Fall wird für jeden von einem Client eingehenden Methodenaufruf eine Serverklasseninstanz erstellt und freigegeben. Der Status einer Serverklasse wird zwischen Methodenaufrufen nicht beibehalten.

Zur Bereitstellung der Kommunikation zwischen dem Client und dem Server ist eine weitere Komponente erforderlich.

Die Komponente TDSTCPServerTransport implementiert einen Multithread-TCP-Server, der eingehende Client-Verbindungen über mehrere Threads empfängt. Diese Komponente hat keine Ereignisse. Die Eigenschaft Port gibt den zu verwendenden TCP-Port an. Per Vorgabe ist dies der Port 211. Sie können auch HTTP für die Kommunikation zwischen dem Client und dem Server verwenden.

Serveranwendung erstellen

  1. Erstellen Sie ein neues Projekt:
    • Delphi: Wählen Sie im Hauptmenü Datei > Neu > VCL-Formularanwendung - Delphi.
    • C++: Wählen Sie im Hauptmenü Datei > Neu > VCL-Formularanwendung - C++Builder.
    Ändern Sie die Eigenschaft Caption des Formulars in ServerForm.
  2. Platzieren Sie die folgenden Komponenten aus der Kategorie DataSnap-Server der Tool-Palette auf dem Formular:
Wählen Sie im Hauptmenü Datei > Alles speichern. Speichern Sie die Datei unter dem Namen MyServer und das Projekt unter dem Namen MyServerProj.
Jetzt sollte Ihre Serveranwendung etwa folgendermaßen aussehen:
DS App1.jpg


Führen Sie die folgenden Schritte aus, um die drei Komponenten miteinander zu verknüpfen:
  • Wählen Sie die TDSServerClass-Komponente auf dem Formular aus. Setzen Sie deren Eigenschaft Server auf den Namen Ihrer TDSServer-Komponente (DSServer1 in diesem Beispiel).
  • Wählen Sie die TDSTCPServerTransport-Komponente auf dem Formular aus. Setzen Sie deren Eigenschaft Server auf den Namen Ihrer TDSServer-Komponente (DSServer1 in diesem Beispiel).
  1. Fügen Sie dem Projekt eine neue Unit hinzu.
    • Delphi: Wählen Sie im Hauptmenü Datei > Neu > Unit - Delphi.
    • C++: Wählen Sie im Hauptmenü Datei > Neu > Unit - C++Builder.
    Speichern Sie die Unit in die Datei MyClass.pas (Delphi) oder MyClass.cpp (C++). Diese Unit enthält die Implementierung der Klassen des Servers, die in der Client-Anwendung verwendet werden sollen. In diesem Beispiel stellt der folgende Code die Implementierung einer Klasse namens MyClass dar, die ein Methode enthält: die Summe zweier Gleitkommazahlen:

    Delphi

    unit MyClass;
    
    interface
    uses Classes;
    type
      {$METHODINFO ON}
      TMyClass = class(TComponent)
        function Sum(const A, B: Double): Double;
      end;
      {$METHODINFO OFF}
    
    implementation
    { TMyClass }
    function TMyClass.Sum(const A, B: Double): Double;
    begin
      Result := A + B;
    end;
    
    end.
    

    Hinweis: Die Direktive {$METHODINFO ON} bewirkt das Erzeugen der vom DataSnap-Server benötigten Laufzeitinformationen. Sie ist daher erforderlich und nicht nur ein Kommentar! Siehe METHODINFO-Direktive (Delphi) für weitere Informationen.

     

    C++

    Kopieren Sie den folgenden Code in MyClass.h:

    # include <DSServer.hpp>
    
    class DECLSPEC_DRTTI TMyClass : public TComponent
    {
    private:
    public:
      double Sum(const double A, const double B);
    };
    # endif
    

    Kopieren Sie den folgenden Code in MyClass.cpp:

    double TMyClass::Sum(const double A, const double B)
    {
      return A + B;
    }
    

    Hinweis: DataSnap unterstützt RTTI beim Entwurf von C++-Anwendungen. Die Deklaration DECLSPEC_DRTTI bewirkt – wie die Direktive {$METHODINFO ON} in Delphi – das Erzeugen der vom DataSnap-Server benötigten Laufzeitinformationen und ist deshalb erforderlich.

    • Fügen Sie für Delphi den Namen dieser Unit, MyClass, der uses-Klausel der Unit MyServer.pas der Serveranwendung hinzu.
    • Fügen Sie für C++ diese Zeile in MyServer.h ein:
    #include "MyClass.h"
    
  2. Um die Klasse festzulegen, die aus der Client-Anwendung aufgerufen werden soll, definieren Sie das Ereignis OnGetClass für die Komponente TDSServerClass. Führen Sie im Formular-Designer für MyServer Folgendes aus:
    1. Wählen Sie die TDSServerClass-Komponente auf dem Formular aus.
    2. Aktivieren Sie im Objektinspektor die Registerkarte Ereignisse.
    3. Doppelklicken Sie auf den Wert des Ereignisses OnGetClass.
    4. Fügen Sie in die erzeugte Funktion eine Quellcodezeile ein, die PersistentClass setzt:

    Delphi

    procedure TForm1.DSServerClass1GetClass(DSServerClass: TDSServerClass;
      var PersistentClass: TPersistentClass);
    begin
      PersistentClass := TMyClass;
    end;
    

    C++

    void __fastcall TForm1::DSServerClass1GetClass(TDSServerClass *DSServerClass, TPersistentClass &PersistentClass)
    
    {
      PersistentClass = __classid(TMyClass);
    }
    
    Wenn Sie dieses Ereignis nicht implementieren, löst die Anwendung sofort nach dem Start eine TDBXError-Exception mit dieser Meldung aus:
    OnGetClass-Ereignis nicht gesetzt, oder Ereignis hat keine Klassenreferenz bereitgestellt
    Das Ereignis OnGetClass hat das Argument PersistentClass, das per Referenz übergeben wird. Im Ereignisbehandlungscode muss der Entwickler PersistentClass eine Klassenreferenz auf eine Serverklasse – wie im obigen Beispiel – zuordnen.
    Dies ist wahrscheinlich das wichtigste Konzept, das bei der DataSnap-Architektur verstanden werden muss. Eine Klassenreferenz wird einer PersistentClass zugeordnet — nicht einer Objektreferenz.

Damit ist die Implementierung der Serveranwendung abgeschlossen.

Client-Anwendung erstellen

  1. Um die Client-Anwendung in derselben Projektgruppe wie die Serveranwendung zu erstellen, klicken Sie in der Projektverwaltung mit der rechten Maustaste auf Ihre Projektgruppe und wählen Neues Projekt hinzufügen, oder wählen Sie aus dem Hauptmenü Projekt > Neues Projekt hinzufügen. Das Dialogfeld Objektgalerie wird geöffnet.
    • Delphi: Wählen Sie die Kategorie Delphi-Projekte, dann VCL-Formularanwendung, und klicken Sie auf OK.
    • C++: Wählen Sie die Kategorie C++Builder-Projekte, dann VCL-Formularanwendung, und klicken Sie auf OK.
    Setzen Sie die Eigenschaften Caption und Name des Formulars auf ClientForm. Wählen Sie im Hauptmenü Datei > Alles speichern. Speichern Sie die Datei unter dem Namen MyClient und das Projekt unter dem Namen MyClientProj. Speichern Sie die Projektgruppe unter dem Namen DSServerExample.
  2. Fügen Sie dem Client-Formular die Steuerelemente hinzu, die für die Eingabedaten und für das Ergebnis (Beschriftungen, Eingabefelder und eine Schaltfläche zum Berechnen der Summe) benötigt werden, wie in der folgenden Abbildung gezeigt. Ändern Sie die Eigenschaft Name von TEdit neben der Beschriftung A in EditA, und ändern Sie die Eigenschaft Name von TEdit für B in EditB. Setzen Sie die Eigenschaft Name des Result-TEdit auf EditResult. Setzen Sie die Eigenschaft Text aller TEdit-Steuerelemente auf einen leeren Wert. Setzen Sie die Eigenschaft Caption von TButton auf Calculate.
  3. Fügen Sie eine TSQLConnection-Komponente aus der Kategorie dbExpress der Tool-Palette hinzu. Setzen Sie für TSQLConnection die folgenden Eigenschaften:
    • Driver: Datasnap (aus der Perspektive des Clients sieht dieser Provider wie eine Verbindung zu einer Datenbank aus, stellt aber tatsächlich die Konnektivität zu den DataSnap-Servern her).
    • LoginPrompt: False (optional, um zu verhindern, dass das Anmelde-Dialogfeld jedes Mal angezeigt wird, wenn der Client eine Verbindung zum Server herstellt).
Das Client-Formular sollte nun etwa folgendermaßen aussehen:
DSAppClientForm.png


  1. Der wichtigste Schritt beim Entwickeln der Client-Serveranwendung mit DataSnap ist das Erstellen des Interface, das den Prototyp aller auf dem Server implementierten Funktionen enthält. Führen Sie Folgendes aus:
    • Wählen Sie das Serverprojekt aus, indem Sie in der Projektverwaltung auf den Namen des Projekts, MyServerProj, doppelklicken.
    • Wählen Sie im Hauptmenü Start > Ohne Debugger ausführen, um den Server zu starten. Sie können das angezeigte ServerForm-Dialogfeld minimieren.
    • Wenn der Server ausgeführt wird, wählen Sie das Client-Projekt, indem Sie in der Projektverwaltung auf dessen Namen, MyClientProj, doppelklicken.
    • Setzen Sie im Formular-Designer die Eigenschaft Connected der TSQLConnection-Komponente auf True.
    • Klicken Sie die TSQLConnection-Komponente auf dem Client-Formular mit der rechten Maustaste an, und wählen Sie aus dem Kontextmenü DataSnap-Client-Klassen erzeugen. Ihrem Client-Projekt wird eine neue Unit hinzugefügt, die Informationen über die auf dem Server implementierten Klassen und alle in diesen Klassen enthaltenen Methoden enthält.
      • Delphi: Speichern Sie die neue Unit unter dem Namen MyDSClient.pas, und fügen Sie der Unit-Liste in MyClient.pas den Unit-Namen, MyDSClient, hinzu.
      • C++: Speichern Sie die neue Unit unter dem Namen MyDSClient.cpp. Fügen Sie die Zeile #include "MyDSClient.h" am Beginn von MyClient.cpp ein.
  2. Rufen Sie nun die gewünschten Methoden in der Client-Anwendung auf. Implementieren Sie für dieses Beispiel das Ereignis OnClick für die TButton-Komponente, um die Methode Sum der gerade automatisch erzeugten DataSnap-Client-Unit aufzurufen. Hier heißt die generierte Klasse TMyClassClient und die Ereignisbehandlungsmethode der Schaltfläche heißt TClientForm.CalculateClick (Delphi) oder TClientForm::Button1Click (C++).
  3. Delphi

    procedure TClientForm.CalculateClick(Sender: TObject);
    var
      Temp: TMyClassClient;
      A, B: Double;
    begin
      Temp := TMyClassClient.Create(SQLConnection1.DBXConnection);
    try
      A := StrToFloat(EditA.Text);
      B := StrToFloat(EditB.Text);
      EditResult.Text := FloatToStr(Temp.Sum(A, B));
    finally
      Temp.Free;
    end;
    

    C++

    void __fastcall TClientForm::Button1Click(TObject *Sender)
    {
      TMyClassClient *Temp;
      double A, B;
    
      Temp = new TMyClassClient(SQLConnection1->DBXConnection);
      try
      {
        A = StrToFloat(EditA->Text);
        B = StrToFloat(EditB->Text);
        EditResult->Text = FloatToStr(Temp->Sum(A, B));
      }
      __finally
      {
        delete Temp;
      }
    }
    
  4. Erzeugen Sie nun die Anwendung, und führen Sie sie aus. Das Client-Formular wird angezeigt. Geben Sie in die Felder A und B Dezimalzahlen ein, klicken Sie auf die Schaltfläche Calculate. Die Summe der beiden Zahlen sollte im Feld Result angezeigt werden.
  5. Wenn Sie eine Fehlermeldung mit dem folgenden Text erhalten

    Verbindung darf nicht nil sein. Überprüfen Sie, ob die Verbindung geöffnet wurde.

    haben Sie wahrscheinlich die Eigenschaft Connected der TSQLConnection-Komponente nicht auf True gesetzt.

DSAppClientRunning.png


Hinweis: Schließen Sie vor dem Beenden der Serveranwendung alle SQL-Verbindungen. Setzen Sie für dieses Beispiel die Eigenschaft Connected der TSQLConnection-Komponente auf False. DataSnap gibt keine Warnung über ausstehende Verbindungen aus. Der Server wird erst geschlossen, wenn keine Verbindungen mehr zu ihm bestehen. Das Schließen aller Client-Anwendungen löst das Problem nicht, weil die Delphi-IDE eine Verbindung zu dem Server automatisch öffnen und nach bereitgestellten Klassen und Methoden suchen kann.

Siehe auch