API SignalRCore

SignalRCore

 

ASP.NET Core SignalR es una biblioteca de código abierto que simplifica la incorporación de funcionalidad web en tiempo real a las aplicaciones. La funcionalidad web en tiempo real permite que el código del lado del servidor envíe contenido a los clientes de forma instantánea.

 

Buenos candidatos para SignalR:

 

 

El componente SignalRCore de sgcWebSockets utiliza WebSocket como transporte para conectarse a un servidor SignalRCore; si este transporte no es compatible, se generará un error.

 

Hubs

SignalRCore utiliza hubs para comunicarse entre clientes y servidores. SignalRCore ofrece 2 protocolos de hub: el protocolo de texto basado en JSON y el protocolo binario basado en MessagePack. El componente sgcWebSockets solo implementa el protocolo de texto JSON para comunicarse con servidores SignalRCore.

Para configurar qué Hub utilizará el cliente, simplemente establezca en la propiedad SignalRCore/Hub el nombre del Hub antes de que el cliente se conecte al servidor.

 

Conexión

Cuando un cliente abre una nueva conexión al servidor, envía un mensaje de solicitud que contiene el protocolo de formato y la versión. sgcWebSockets siempre envía el protocolo de formato como JSON. El servidor responderá con un error si el protocolo no es compatible, este error puede gestionarse mediante el evento OnSignalRCoreError, y si la conexión es exitosa, se llamará al evento OnSignalRCoreConnect.

 

Cuando un cliente se conecta a un servidor SignalRCore, puede enviar un ConnectionId que identifica al cliente entre sesiones, de modo que si se produce una desconexión el cliente puede volver a conectarse al servidor pasando el mismo id de conexión anterior. Para obtener un nuevo id de conexión, simplemente conéctese normalmente al servidor y podrá conocer el ConnectionId usando OnBeforeConnectEvent. Si desea volver a conectarse al servidor y pasar un id de conexión anterior, use el método ReConnect y pase ConnectionId como parámetro.

 

 

SignalRCore Protocol

El protocolo SignalR es un protocolo de RPC bidireccional sobre cualquier transporte basado en mensajes. Cualquiera de las partes de la conexión puede invocar procedimientos en la otra parte, y los procedimientos pueden devolver cero o más resultados o un error. Ejemplo: el cliente puede solicitar un método del servidor y el servidor puede solicitar un método del cliente. Los siguientes mensajes se intercambian entre servidor y clientes:

 

 

 

SignalRCore Codificación

 

SignalRCore permite utilizar las siguientes codificaciones:

 

 

Actualmente, solo se admite JSON, aunque MessagePack puede utilizarse codificando los mensajes enviados mediante una biblioteca messagepack externa. Consulte la sección MessagePack a continuación para obtener más información.

 

La configuración del protocolo de codificación se define en la propiedad SignalRCore.Protocol. De forma predeterminada, el valor es srcpJSON.

 

Autorización

Se puede habilitar la autenticación para asociar un usuario con cada conexión y filtrar qué usuarios pueden acceder a los recursos. La autenticación se implementa mediante Bearer Tokens: el cliente proporciona un token de acceso y el servidor valida este token y lo utiliza para identificar al usuario.

En las API web estándar, los tokens bearer se envían en una cabecera HTTP, pero cuando se usan websockets, el token se transmite como parámetro de cadena de consulta.

Se admiten los siguientes métodos:

 

srcaRequestToken

 

Si la autenticación está habilitada, el flujo es:

 

1. Primero intenta obtener un token válido del servidor. Abre una conexión HTTP contra Authentication.RequestToken.URL y realiza un POST usando los datos de usuario y contraseña.

2. Si el paso anterior es exitoso, se devuelve un token. De lo contrario, se devuelve un error.

3. Si se devuelve el token, se abre una nueva conexión HTTP para negociar una nueva conexión. Aquí, el token se pasa como encabezado HTTP.

4. Si lo anterior tiene éxito, abre una conexión WebSocket y pasa el token como parámetro de cadena de consulta.

 

 

srcaSetToken

 

Aquí, el token se pasa directamente al servidor SignalRCore (porque el token se ha obtenido de otro servidor).

 

 

 

El token de acceso puede enviarse como parámetro de consulta (esta es la opción predeterminada) o como cabecera HTTP en forma de Bearer Token. Use la propiedad Authentication.TokenParam para configurar este comportamiento.

 

 

 

srcaBasic

 

Esta opción usa Basic Authentication; este método de autenticación requiere configurar el componente SignalRCore y el TsgcWebSocketClient.

 

Ejemplo: si el servidor requiere autenticación básica y el nombre de usuario es "user" y la contraseña es "secret", configure los componentes como se muestra a continuación.

 


// 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;

 

Comunicación entre cliente y servidor

Existen tres tipos de interacciones entre el servidor y los clientes:

 

Invocaciones

El Caller envía un mensaje al Callee y espera un mensaje que indique que la invocación ha sido completada y, opcionalmente, un resultado de la invocación

Ejemplo: el cliente invoca el método SendMessage y pasa como parámetros el nombre de usuario y el mensaje de texto. Envía un ID de invocación para
obtener un mensaje de resultado del servidor.


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;

Invocaciones no bloqueantes

El Caller envía un mensaje al Callee y no espera más mensajes para esta invocación. Las invocaciones pueden enviarse sin un valor de ID de invocación. Esto indica que la invocación es "no bloqueante".

Ejemplo: el cliente invoca el método SendMessage y pasa como parámetros el nombre de usuario y el mensaje de texto. El cliente no espera ninguna respuesta del servidor sobre el resultado de la invocación.

 


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

Invocaciones en streaming

El Caller envía un mensaje al Callee y espera uno o más resultados devueltos por el Callee, seguidos de un mensaje que indica el fin de la invocación.

Ejemplo: el cliente invoca el método Counter y solicita 10 números con un intervalo de 500 milisegundos.


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;

Invocaciones

Para realizar una invocación única, el Caller sigue el siguiente flujo básico:


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

Asigne un valor de ID de invocación único (cadena arbitraria, elegida por el llamador) para representar la invocación. Llame al método Invoke o InvokeStream con el Target que se va a invocar, los Arguments y el InvocationId (si no envía InvocationId, no recibirá el resultado de finalización).

 

Si la Invocación está marcada como no bloqueante (véase "Invocaciones No Bloqueantes" a continuación), detenga aquí y devuelva el control inmediatamente a la aplicación. Gestione el mensaje StreamItem o Completion con un ID de Invocación coincidente.


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;

Puede realizar una invocación individual y esperar a que se complete.

 


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;

Asigne un valor de ID de invocación único (cadena arbitraria, elegida por el llamante) para representar la invocación. Llame al método InvokeAndWait o InvokeStreamAndWait indicando el objetivo que se invoca, los argumentos y el InvocationId. El programa esperará hasta que se llame al evento de finalización o se supere el tiempo de espera.


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;

Cancelar invocación

Si el cliente desea dejar de recibir mensajes StreamItem antes de que el servidor envíe un mensaje Completion, puede enviar un mensaje CancelInvocation con el mismo InvocationId utilizado en el mensaje StreamInvocation que inició el flujo.


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

Resultados del Cliente

 

Una invocación solo se considera completada cuando se recibe el mensaje de finalización. Si el cliente recibe una invocación del servidor, se invocará el evento OnSignalRCoreInvocation.


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

Cerrar conexión

 

Enviado por el cliente cuando se cierra una conexión. Contiene un motivo de error si la conexión se cerró a causa de un error.


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

El protocolo SignalR Hub admite mensajes "Keep Alive" utilizados para garantizar que la conexión de transporte subyacente permanezca activa. Estos mensajes ayudan a garantizar:

Los proxies no cierran la conexión subyacente durante períodos de inactividad (cuando se envían pocos mensajes). Si la conexión subyacente se interrumpe sin cerrarse correctamente, la aplicación es informada lo antes posible.

El comportamiento de keep alive se logra llamando al método Ping o habilitando HeartBeat en el cliente WebSocket. Si el servidor envía un ping al cliente, el cliente enviará automáticamente una respuesta y se invocará el evento OnSignalRCoreKeepAlive.


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

MessagePack

En la codificación MsgPack del protocolo SignalR, cada mensaje se representa como un único array MsgPack que contiene elementos correspondientes a las propiedades del mensaje del protocolo hub dado. Los elementos del array pueden ser valores primitivos, arrays (por ejemplo, argumentos de método) u objetos (por ejemplo, valor de argumento). El primer elemento del array es el tipo de mensaje.

 

Consulte la documentación de MessagePack para ver cómo codificar los mensajes enviados.

 

Cada vez que se recibe un nuevo mensaje, este se despacha en el evento OnSignalRCoreMessagePack. Se puede acceder al mensaje leyendo el parámetro Data Stream. El parámetro JSON está vacío por defecto; si convierte el mensaje MessagePack a JSON, el componente procesará el mensaje JSON como si la codificación fuera JSON (por lo que se despacharán los eventos OnSignalRCoreCompletion, OnSignalRCoreInvocation...).