RPC/RMI
How to define methods on the client that the server can call
You define the methods per Controller
since one connection can communicate over several Controllers
Client
The example below creates a listener for ChatMessage
and it expects the data to be a string.
conn.Controller("chat").On<string>("chatmessage", data => Console.WriteLine(data));
Server
The server code for the examples with the ChatModel
can look like
//using XSockets.Core.XSocket;
//using XSockets.Core.XSocket.Helpers;
this.InvokeToAll("I am Yogi the gummi bear","chatmessage");
Methods without parameters
If the method you're handling does not have parameters just use the non generic On
method.
Server
//using XSockets.Core.XSocket;
//using XSockets.Core.XSocket.Helpers;
public class Chat : XSocketController
{
public async Task CallAllClients()
{
await this.InvokeToAll("test");
}
}
Note: You can of course use InvokeTo<T>
or Invoke
as well
Client
conn.Controller("chat").On("test", () => Console.WriteLine("Test Was Called"));
Methods with parameters, specifying parameter types
If we have a complex object being sent from the server, like the ChatModel
we can of course just do like this
conn.Controller("chat").On<ChatModel>("chatmessage", data => Console.WriteLine(data.UserName + " - " + data.Text));
Server
The server code for the examples with the ChatModel
can look like
//using XSockets.Core.XSocket;
//using XSockets.Core.XSocket.Helpers;
this.InvokeToAll(new ChatModel{Name="Yogi", Text="I am a gummi bear"},"chatmessage");
Methods with parameters, specifying dynamic objects for the parameters
As an alternative to specifying specific types to the On method, you can specify parameters as dynamic objects.
conn.Controller("chat").On<dynamic>("chatmessage", data => Console.WriteLine(data.Text));
Note: Dynamic keyword will (currently) not exist in clients for Android/iOS. Note: Dynamic keyword does not exist in .NET 3.5 and earlier.
Server
The server code for the examples with the ChatModel
can look like
//using XSockets.Core.XSocket;
//using XSockets.Core.XSocket.Helpers;
this.InvokeToAll(new ChatModel{Name="Yogi", Text="I am a gummi bear"},"chatmessage");
Methods with parameter of type IMessage
If you for some reason want the actual IMessage sent from the server to the client you can specify IMessage as the type. You will then get the complete object that the client received!
conn.Controller("chat").On<IMessage>("chatmessage", o => Console.WriteLine("{0}, {1} {2}, {3},",o.Controller, o.Topic, o.Data, o.MessageType);
If you know the type contained in the Data part of the IMessage you can use Extract
//example extracting the JSON into a specific type
var chatModel = o.Extract<ChatModel>();
Server
The server code for the examples with the ChatModel
can look like
//using XSockets.Core.XSocket;
//using XSockets.Core.XSocket.Helpers;
this.InvokeToAll(new ChatModel{Name="Yogi", Text="I am a gummi bear"},"chatmessage");
How to remove a handler
When you want to dispose of a handler you have to remove it from the Controller
where it was used.
var listener = conn.Controller("chat").On<string>("chatmessage", data => Console.WriteLine(data));
conn.Controller("chat").DisposeListener(listener);
How to send to server methods from the client
To call a method on the server, use the Invoke method on the Controller
.
If the server method has no return value, use the non-generic overload of the Invoke method.
Server - method without return value
//using XSockets.Core.XSocket;
public class Chat : XSocketController
{
protected string UserName {get;set;}
public void SetUserName(string userName)
{
this.UserName = userName;
}
}
Client - calling a method that has no return value
conn.Controller("chat").Invoke("setusername", new {userName = "Steve"});
How to call a server side method and wait for the result
If the server method has a return value, specify the return type as the generic type of the Invoke method.
Server - for a method that has a return value
public IEnumerable<Stock> GetStocks()
{
return _stockTicker.GetAllStocks();
}
The Stock class used for return value
public class Stock
{
public string Symbol { get; set; }
public decimal Price { get; set; }
}
Client - calling a method that has a return value in a synchronous method
var stocks = await conn.Controller("stockticker").Invoke<IEnumerable<Stock>>("GetStocks");
foreach (Stock stock in stocks.Result)
{
Console.WriteLine("Symbol: {0} price: {1}\n", stock.Symbol, stock.Price);
}
If there is no response for 30000 ms there will be a TimeoutException
so you should wrap the synchronous call like:
try
{
var stocks = await conn.Controller("stockticker").Invoke<IEnumerable<Stock>>("GetStocks");
foreach (Stock stock in stocks.Result)
{
Console.WriteLine("Symbol: {0} price: {1}\n", stock.Symbol, stock.Price);
}
}
catch (AggregateException ae)
{
ae.Handle((x) =>
{
if (x is TimeoutException)
{
//The communication did not respond within given time frame
//Handle it...
return true;
}
//Another exception handle it... or return false to stop app
return false;
});
}
Of course you can set the default 30000 ms to be longer or shorter if needed. Just pass in your timeout as a parameter in the call like
//Timeout will now be 5 seconds
var stocks = await conn.Controller("stockticker").Invoke<IEnumerable<Stock>>("GetStocks",5000);