ThothRPC es un marco de RPC para .NET, holístico, totalmente compatible con AOT, liviano, dúplex y bidireccional para .NET. Es completamente simple pero poderoso. Es completamente de plataforma agnóstica y modular, sin hacer suposiciones de qué tipo de proyecto está construyendo. Las capas de transporte y serialización de objetos (para parámetros y retornos de métodos) están separadas de la biblioteca base y la implementación personalizada de estas capas son fáciles de hacer que le brinde la libertad para construir fácilmente su propio sistema RPC.
Por supuesto, no sería simple si estas capas no estuvieran incluidas para usted. Esta biblioteca viene con una capa de transporte UDP confiable y ordenada construida a partir de litenetlib y una capa de serialización construida en un paquete de mensajes rápido con una solución de transporte web segura basada en la web HTTP/2 en la hoja de ruta.
Para usar el siguiente código de muestra, necesita estos 3 paquetes Nuget.
dotnet add package ThothRpc
dotnet add package ThothRpc.LiteNetLib
dotnet add package ThothRpc.MessagePack
--o--
Install-Package ThothRpc
Install-Package ThothRpc.LiteNetLib
Install-Package ThothRpc.MessagePack
public interface IClientService
{
[ ThothMethod ] // indicates that this method is callable from server
void PrintServerTime ( DateTime time ) ;
Task GetHelloWorld ( ) ;
}
public interface IServerService
{
[ ThothMethod ] // indicates that this method is callable from client
string GetHelloWorld ( ) ;
} // hubs are thread-safe and can be single instanced for your entire app,
// or you can have multiple instances - its up to you
var hub = ServerHubBuilder . BuildServer ( )
. UseTransport < LiteNetRpcServer > ( )
. UseMessagePack ( ) // any object that is serializable by MessagePack can be used in parameters or return values
. Build ( ) ;
var serverService = new ServerService ( hub ) ;
// register methods can be called multiple times to register multiple services to the same hub
hub . RegisterAs < IServerService > ( serverService ) ;
hub . Listen ( 9050 , "SomeConnectionKey" ) ;
// Thread.Sleep(60000);
// hub.Dispose(); // closes the connection
public class ServerService : IServerService
{
readonly ServerHub _hub ;
public ServerService ( ServerHub hub )
{
_hub = hub ;
Task . Run ( async ( ) =>
{
// print the current time to all clients every second
while ( true )
{
var now = DateTime . Now ;
// Fire and forget
_hub . InvokeForgetAllClients < IClientService > ( DeliveryMode . Sequenced ,
c => c . PrintServerTime ( now ) ) ;
await Task . Delay ( 1000 ) ;
}
} ) ;
}
public string GetHelloWorld ( ) // called from client
{
return "Hello World From Server!" ;
}
} var hub = ClientHubBuilder . BuildClient ( )
. UseTransport < LiteNetRpcClient > ( )
. UseMessagePack ( )
. Build ( ) ;
var clientService = new ClientService ( hub ) ;
hub . RegisterAs < IClientService > ( clientService ) ;
await hub . ConnectAsync ( "localhost" , 9050 , "SomeConnectionKey" ) ;
await clientService . GetHelloWorld ( ) ;
public class ClientService : IClientService
{
readonly ClientHub _hub ;
public ClientService ( ClientHub hub )
{
_hub = hub ;
}
public async Task GetHelloWorld ( )
{
// Method invocations not using fire-and-forget with a udp transport are always delivered reliable and ordered.
var helloWorld = await _hub . InvokeServerAsync < IServerService , string >
( s => s . GetHelloWorld ( ) ) ;
Console . WriteLine ( helloWorld ) ;
}
public void PrintServerTime ( DateTime time ) // called from server
{
Console . WriteLine ( $ "Server time: { time } " ) ;
}
}El código a continuación es el mismo que el anterior, pero esta vez sin ningún tipo de mecanografía fuerte.
var hub = ServerHubBuilder . BuildServer ( )
. UseTransport < LiteNetRpcServer > ( )
. UseMessagePack ( )
. Build ( ) ;
var serverService = new ServerService ( hub ) ;
hub . Register ( serverService , "ServerService" ) ;
hub . Listen ( 9050 , "SomeConnectionKey" ) ;
public class ServerService
{
readonly ServerHub _hub ;
public ServerService ( ServerHub hub )
{
_hub = hub ;
Task . Run ( async ( ) =>
{
while ( true )
{
_hub . InvokeForgetAllClients ( DeliveryMode . Sequenced ,
"ClientService" , "PrintServerTime" , DateTime . Now ) ;
await Task . Delay ( 1000 ) ;
}
} ) ;
}
[ ThothMethod ]
public string GetHelloWorld ( )
{
return "Hello World From Server!" ;
}
} var hub = ClientHubBuilder . BuildClient ( )
. UseTransport < LiteNetRpcClient > ( )
. UseMessagePack ( )
. Build ( ) ;
var clientService = new ClientService ( hub ) ;
hub . Register ( clientService , "ClientService" ) ;
await hub . ConnectAsync ( "localhost" , 9050 , "SomeConnectionKey" ) ;
await clientService . GetHelloWorld ( ) ;
public class ClientService
{
readonly ClientHub _hub ;
public ClientService ( ClientHub hub )
{
_hub = hub ;
}
public async Task GetHelloWorld ( )
{
var helloWorld = await _hub . InvokeServerAsync < string >
( "ServerService" , "GetHelloWorld" ) ;
Console . WriteLine ( helloWorld ) ;
}
[ ThothMethod ]
public void PrintServerTime ( DateTime time )
{
Console . WriteLine ( $ "Server time: { time } " ) ;
}
} Thoth (en su estado actual) es excelente para ...
Nota: El tráfico asegurado actualmente cifrado aún no es una característica, pero estará presente en el próximo transporte HTTP/2. Sin embargo, implementar su propio sistema de cifrado es fácil con las devoluciones de llamada de entrada y salida.