API SignalRCore

SignalRCore

 

ASP.NET Core SignalR ist eine Open-Source-Bibliothek, die das Hinzufügen von Echtzeit-Webfunktionalität zu Apps vereinfacht. Echtzeit-Webfunktionalität ermöglicht es serverseitigem Code, Inhalte sofort an Clients zu pushen.

 

Gute Kandidaten für SignalR:

 

 

Die SignalRCore-Komponente von sgcWebSockets verwendet WebSocket als Transport, um eine Verbindung zu einem SignalRCore-Server herzustellen. Wenn dieser Transport nicht unterstützt wird, wird ein Fehler ausgelöst.

 

Hubs

SignalRCore verwendet Hubs zur Kommunikation zwischen Clients und Servern. SignalRCore bietet 2 Hub-Protokolle: ein Textprotokoll basierend auf JSON und ein Binärprotokoll basierend auf MessagePack. Die sgcWebSockets-Komponente implementiert nur das JSON-Textprotokoll zur Kommunikation mit SignalRCore-Servern.

Um zu konfigurieren, welchen Hub der Client verwendet, setzen Sie einfach in der Eigenschaft SignalRCore/Hub den Namen des Hubs, bevor sich der Client mit dem Server verbindet.

 

Verbindung

Wenn ein Client eine neue Verbindung zum Server öffnet, sendet er eine Anforderungsnachricht, die Formatprotokoll und Version enthält. sgcWebSockets sendet das Formatprotokoll immer als JSON. Der Server antwortet mit einem Fehler, wenn das Protokoll vom Server nicht unterstützt wird; dieser Fehler kann mit dem Ereignis OnSignalRCoreError behandelt werden, und wenn die Verbindung erfolgreich ist, wird das Ereignis OnSignalRCoreConnect aufgerufen.

 

Wenn sich ein Client mit einem SignalRCore-Server verbindet, kann er eine ConnectionId senden, die den Client zwischen Sitzungen identifiziert, sodass der Client bei einer Trennung erneut eine Verbindung zum Server herstellen kann, indem er dieselbe vorherige Verbindungs-ID übergibt. Um eine neue Verbindungs-ID zu erhalten, verbinden Sie sich einfach normal mit dem Server, und Sie können die ConnectionId über OnBeforeConnectEvent erfahren. Wenn Sie sich erneut mit dem Server verbinden und eine vorherige Verbindungs-ID übergeben möchten, verwenden Sie die Methode ReConnect und übergeben Sie ConnectionId als Parameter.

 

 

SignalRCore Protocol

Das SignalR-Protokoll ist ein Protokoll für bidirektionalen RPC über jeden nachrichtenbasierten Transport. Jede Partei in der Verbindung kann Prozeduren auf der anderen Partei aufrufen, und Prozeduren können null oder mehr Ergebnisse oder einen Fehler zurückgeben. Beispiel: der Client kann eine Methode vom Server anfordern und der Server kann eine Methode vom Client anfordern. Die folgenden Nachrichten werden zwischen Server und Clients ausgetauscht:

 

 

 

SignalRCore Encoding

 

SignalRCore ermöglicht die Verwendung der folgenden Codierungen:

 

 

Derzeit wird nur JSON unterstützt, obwohl MessagePack verwendet werden kann, indem die gesendeten Nachrichten mit einer externen MessagePack-Bibliothek kodiert werden. Siehe den Abschnitt MessagePack unten für weitere Informationen.

 

Die Konfiguration des Encoding-Protokolls wird in der Eigenschaft SignalRCore.Protocol definiert. Standardmäßig ist der Wert srcpJSON.

 

Authorization

Die Authentifizierung kann aktiviert werden, um jeder Verbindung einen Benutzer zuzuordnen und zu filtern, welche Benutzer auf Ressourcen zugreifen können. Die Authentifizierung wird mit Bearer-Tokens implementiert: Der Client stellt ein Access-Token bereit und der Server validiert dieses Token und verwendet es, um den Benutzer zu identifizieren.

In Standard-Web-APIs werden Bearer-Token in einem HTTP-Header gesendet, aber bei Verwendung von WebSockets wird das Token als Query-String-Parameter übertragen.

Die folgenden Methoden werden unterstützt:

 

srcaRequestToken

 

Wenn die Authentifizierung aktiviert ist, lautet der Ablauf:

 

1. Versucht zunächst, ein gültiges Token vom Server abzurufen. Öffnet eine HTTP-Verbindung zu Authentication.RequestToken.URL und führt einen POST mit den Daten User und Password durch.

2. Wenn der vorherige Schritt erfolgreich ist, wird ein Token zurückgegeben. Wenn nicht, wird ein Fehler zurückgegeben.

3. Wenn ein Token zurückgegeben wird, wird eine neue HTTP-Verbindung geöffnet, um eine neue Verbindung auszuhandeln. Hier wird das Token als HTTP-Header übergeben.

4. Wenn der vorherige Schritt erfolgreich ist, wird eine WebSocket-Verbindung geöffnet und das Token als Query-String-Parameter übergeben.

 

 

srcaSetToken

 

Hier übergeben Sie das Token direkt an den SignalRCore-Server (da das Token von einem anderen Server bezogen wurde).

 

 

 

Das Zugriffstoken kann als Abfrageparameter gesendet werden (dies ist die Standardoption) oder als HTTP-Header als Bearer-Token gesendet werden. Verwenden Sie die Eigenschaft Authentication.TokenParam, um dieses Verhalten zu konfigurieren.

 

 

 

srcaBasic

 

Diese Option verwendet Basic-Authentifizierung; diese Authentifizierungsmethode erfordert die Konfiguration der SignalRCore-Komponente und des TsgcWebSocketClient.

 

Beispiel: wenn der Server Basic-Authentifizierung erfordert und der Benutzername "user" und das Passwort "secret" ist, konfigurieren Sie die Komponenten wie unten gezeigt.

 


// websocket client
WSClient := TsgcWebSocketClient.Create(nil);
WSClient.Authentication.Enabled := True;
WSClient.Authentication.Basic.Enabled := True;
WSClient.Authentication.URL.Enabled := False;
WSClient.Authentication.Session.Enabled := False;
WSClient.Authentication.Token.Enabled := False;
WSClient.Authentication.User := 'user';
WSClient.Authentication.Password := 'secret';
// signalrcore
Signal := TsgcWSAPI_SignalRCore.Create(nil);
Signal.SignalRCore.Authentication.Enabled := True;
Signal.SignalRCore.Authentication.Authentication := srcaBasic;
Signal.SignalRCore.Authentication.Username := 'user';
Signal.SignalRCore.Authentication.Password := 'secret';
Signal.Client := WSClient;

 

Communication between Client and Server

Es gibt drei Arten von Interaktionen zwischen Server und Clients:

 

Invocations

Der Caller sendet eine Nachricht an den Callee und erwartet eine Nachricht, die anzeigt, dass der Aufruf abgeschlossen wurde, und optional ein Ergebnis des Aufrufs

Beispiel: Der Client ruft die Methode SendMessage auf und übergibt als Parameter Benutzername und Textnachricht. Sendet eine Invocation Id, um
eine Ergebnisnachricht vom Server zu erhalten.


SignalRCore.Invoke('SendMessage', ['John', 'Hello All.'], 'id-000001');
 
procedure OnSignalRCoreCompletion(Sender: TObject; Completion: TSignalRCore_Completion);
begin
  if Completion.Error <> '' then
    ShowMessage('Something goes wrong.')
  else
    ShowMessage('Invocation Successful!');
end;

Nicht blockierende Aufrufe

Der Caller sendet eine Nachricht an den Callee und erwartet keine weiteren Nachrichten für diesen Aufruf. Aufrufe können ohne einen Invocation-ID-Wert gesendet werden. Dies zeigt an, dass der Aufruf "non-blocking" ist.

Beispiel: Der Client ruft die Methode SendMessage auf und übergibt als Parameter Benutzername und Textnachricht. Der Client erwartet keine Antwort vom Server über das Ergebnis des Aufrufs.

 


SignalRCore.Invoke('SendMessage', ['John', 'Hello All.']);

Streaming Invocations

Der Caller sendet eine Nachricht an den Callee und erwartet ein oder mehrere vom Callee zurückgegebene Ergebnisse, gefolgt von einer Nachricht, die das Ende des Aufrufs anzeigt.

Beispiel: Der Client ruft die Counter-Methode auf und fordert 10 Zahlen mit einem Intervall von 500 Millisekunden an.


SignalRCore.InvokeStream('Counter', [10, 500], 'id-000002');
 
procedure OnSignalRCoreStreamItem(Sender: TObject; StreamItem: TSignalRCore_StreamItem; var Cancel: Boolean);
begin
  DoLog('#stream item: ' + StreamItem.Item);
end;
 
procedure OnSignalRCoreCompletion(Sender: TObject; Completion: TSignalRCore_Completion);
begin
  if Completion.Error  '' then
    ShowMessage('Something goes wrong.')
  else
    ShowMessage('Invocation Successful!');
end;

Invocations

Um einen einzelnen Aufruf durchzuführen, folgt der Caller dem folgenden grundlegenden Ablauf:


procedure Invoke(const aTarget: String; const aArguments: Array of Const; const aInvocationId: String = '');
procedure InvokeStream(const aTarget: String; const aArguments: Array of Const; const aInvocationId: String);

Weisen Sie einen eindeutigen Wert für die Invocation ID zu (beliebige Zeichenfolge, vom Caller gewählt), um den Aufruf zu repräsentieren. Rufen Sie die Methode Invoke oder InvokeStream auf, die das aufzurufende Target, Arguments und InvocationId enthält (wenn Sie keine InvocationId senden, erhalten Sie kein Abschlussergebnis).

 

Wenn der Invocation als nicht blockierend markiert ist (siehe "Non-Blocking Invocations" unten), stoppen Sie hier und kehren Sie sofort zur Anwendung zurück. Behandeln Sie StreamItem- oder Completion-Nachrichten mit einer passenden Invocation-ID.


SignalRCore.InvokeStream('Counter', [10, 500], 'id-000002');
 
procedure OnSignalRCoreStreamItem(Sender: TObject; StreamItem: TSignalRCore_StreamItem; var Cancel: Boolean);
begin
  if StreamItem.InvocationId = 'id-000002' then
    DoLog('#stream item: ' + StreamItem.Item);
end;
 
procedure OnSignalRCoreCompletion(Sender: TObject; Completion: TSignalRCore_Completion);
begin
  if StreamItem.InvocationId = 'id-000002' then
  begin
    if Completion.Error  '' then
      ShowMessage('Something goes wrong.')
    else
      ShowMessage('Invocation Successful!');
  end;
end;

Sie können einen einzelnen Aufruf ausführen und auf den Abschluss warten.

 


function InvokeAndWait(const aTarget: String; aArguments: Array of Const; aInvocationId: String; out Completion: TSignalRCore_Completion; 
  const aTimeout: Integer = 10000): Boolean;
function InvokeStreamAndWait(const aTarget: String; const aArguments: Array of Const; const aInvocationId: String; 
  out Completion: TSignalRCore_Completion; const aTimeout: Integer = 10000): Boolean;

Weisen Sie einen eindeutigen Invocation-ID-Wert (beliebige Zeichenfolge, vom Caller gewählt) zu, um die Invocation darzustellen. Rufen Sie die Methode InvokeAndWait oder InvokeStreamAndWait auf, die das aufzurufende Target, die Arguments und die InvocationId enthält. Das Programm wartet, bis das Completion-Ereignis aufgerufen wird oder das Time-out überschritten wurde.


var
  oCompletion: TSignalRCore_Completion;
begin
  if SignalRCore.InvokeStreamAndWait('Counter', [10, 500], 'id-000002', oCompletion) then
    DoLog('#invoke stream ok: ' + oCompletion.Result)
  else
    DoLog('#invocke stream error: ' + oCompletion.Error);
  
 
procedure OnSignalRCoreStreamItem(Sender: TObject; StreamItem: TSignalRCore_StreamItem; var Cancel: Boolean);
begin
  if StreamItem.InvocationId = 'id-000002' then
    DoLog('#stream item: ' + StreamItem.Item);
end;

Aufruf abbrechen

Wenn der Client das Empfangen von StreamItem-Nachrichten beenden möchte, bevor der Server eine Completion-Nachricht sendet, kann der Client eine CancelInvocation-Nachricht mit derselben InvocationId senden, die für die StreamInvocation-Nachricht verwendet wurde, die den Stream gestartet hat.


procedure OnSignalRCoreStreamItem(Sender: TObject; StreamItem: SignalRCore_StreamItem; var Cancel: Boolean);
begin
  if StreamItem.InvocationId = 'id-000002' then
    Cancel := True;
end;

Client-Ergebnisse

 

Eine Invocation gilt erst dann als abgeschlossen, wenn die Completion-Nachricht empfangen wird. Wenn der Client eine Invocation vom Server empfängt, wird das Ereignis OnSignalRCoreInvocation aufgerufen.


procedure OnSignalRCoreInvocation(Sender: TObject; Invocation: TSignalRCore_Invocation);
begin
  if Invocation.Target = 'SendMessage' then
    ... your code here ...
end;
// Once invocation is completed, call Completion method to inform server invocation is finished.
// If result is successful, then call CompletionResult method:
SignalRCore.CompletionResult('id-000002', 'ok');
 
// If not, then call CompletionError method:
SignalRCore.CompletionError('id-000002', 'Error processing invocation.');

Verbindung schließen

 

Wird vom Client gesendet, wenn eine Verbindung geschlossen wird. Enthält einen Fehlergrund, wenn die Verbindung aufgrund eines Fehlers geschlossen wurde.


SignalRCore.Close('Unexpected message').
  
// If the server close connection by any reason, OnSignalRCoreClose event will be called. 
procedure OnSignalRCoreClose(Sender: TObject; Close: TSignalRCore_Close);
begin
  DoLog('#closed: ' + Close.Error);
end;

Ping

Das SignalR-Hub-Protokoll unterstützt "Keep Alive"-Nachrichten, die verwendet werden, um sicherzustellen, dass die zugrunde liegende Transportverbindung aktiv bleibt. Diese Nachrichten helfen sicherzustellen:

Dass Proxys die zugrunde liegende Verbindung während Leerlaufzeiten nicht schließen (wenn nur wenige Nachrichten gesendet werden). Wenn die zugrunde liegende Verbindung abbricht, ohne ordnungsgemäß beendet zu werden, wird die Anwendung so schnell wie möglich informiert.

Das Keep-Alive-Verhalten wird durch Aufrufen der Ping-Methode oder Aktivieren von HeartBeat auf dem WebSocket-Client erreicht. Wenn der Server einen Ping an den Client sendet, sendet der Client automatisch eine Antwort und das Ereignis OnSignalRCoreKeepAlive wird aufgerufen.


procedure OnSignalRCoreKeepAlive(Sender: TObject);
begin
  DoLog('#keepalive');
end;

MessagePack

In der MsgPack-Codierung des SignalR-Protokolls wird jede Nachricht als einzelnes MsgPack-Array dargestellt, das Items enthält, die Eigenschaften der jeweiligen Hub-Protokoll-Nachricht entsprechen. Die Array-Items können primitive Werte, Arrays (z. B. Methodenargumente) oder Objekte (z. B. Argumentwerte) sein. Das erste Item im Array ist der Nachrichtentyp.

 

Lesen Sie die MessagePack-Dokumentation, um zu sehen, wie die gesendeten Nachrichten codiert werden.

 

Jedes Mal, wenn eine neue Nachricht empfangen wird, wird sie im Ereignis OnSignalRCoreMessagePack zugestellt. Auf die Nachricht kann durch Lesen des Stream-Parameters Data zugegriffen werden. Der Parameter JSON ist standardmäßig leer; wenn Sie die MessagePack-Nachricht in JSON konvertieren, verarbeitet die Komponente die JSON-Nachricht so, als ob die Kodierung JSON verwendet hätte (sodass die Ereignisse OnSignalRCoreCompletion, OnSignalRCoreInvocation... zugestellt werden).