Controllers - XSockets/XSockets.NET-4.0 GitHub Wiki
##Controllers If you are familiar with the MVC pattern you will find it very easy to work with XSockets controllers.
###How to create and use Controller classes
To create a Controller
, create a class that derives from XSockets.Core.XSocket.XSocketController
. The following example shows a simple Controller
class for a chat application.
//using XSockets.Core.XSocket;
//using XSockets.Core.XSocket.Helpers;
public class Chat : XSocketController
{
public void ChatMessage(string message)
{
this.InvokeToAll(message,"chatmessage");
}
}
In this example, a connected client can call the ChatMessage method, and when it does, the data received is broadcasted (RPC) to all clients connected to the Controller
.
####Give the controller an Alias
If you want to specify a different name for clients to use, add the XSocketsMetadata
attribute and set the Alias
to the name you want for the controller. You might wanna do this is you have long and complex names for controller on the server.
Server
//using XSockets.Core.XSocket;
//using XSockets.Plugin.Framework.Attributes;
[XSocketMetadata(PluginAlias = "Chat")]
public class MyToLongAndComplexClassNameForTheChat : XSocketController
And then you can connect using the Alias
as shown below.
Client - JavaScript
var conn = new XSockets.WebSocket('ws://127.0.0.1:4502',['chat']);
Client - C#
var conn = new XSocketsClient("ws://127.0.0.1:4502","http://localhost","chat");
####Controller object lifetime
You don't instantiate the Controller
class or call its methods from your own code on the server. This is all done for you by the XSockets.NET plugin framework. XSockets.NET creates a new instance of your Controller the first time you use it on you connection. The Controller
will live in memory for as long as the client is connected to it. This provides the possibility to have state on the controllers which is the most important feature when working with real-time frameworks.
Because the instances of the 'Controller' class ARE transient, you can use them to maintain state from one method call to the next. Each time the server receives a method call from the client, it will be the same instance of your ´Controller´ class per connection that processes the message. Since XSockets.NET does not recycle you will not loose data even though it is stored in-memory. Of course you should persist information that is important since information will be lost if/when the server is stopped.
If you want to send messages to clients from your own code that runs outside the Controller
class but in the same context as the server, you can do it by instantiating a Controller
class instance. Note: Instances created like this will not have a socket but they can still be used to send messages to clients connected on any Controller
.
####How to define methods in the Controller class that the clients can call
To expose a method on the Controller
that you want to be callable from the client, declare a public method, as shown in the following examples.
//using System.Collections.Generic;
//using XSockets.Core.XSocket;
//using XSockets.Core.XSocket.Helpers;
public class Chat : XSocketController
{
public void ChatMessage(string message)
{
this.InvokeToAll(message,"chatmessage");
}
}
public class StockTicker : XSocketController
{
public IEnumerable<Stock> GetAllStocks()
{
return _stockTicker.GetAllStocks();
}
}
You can specify a return type and parameters, including complex types and arrays, as you would in any C# method. Any data that you receive in parameters or return to the caller is communicated between the client and the server by using JSON, and XSockets.NET handles the binding of complex objects and arrays of objects automatically.
####How to call client methods from the Controller class
To call client methods from the server, use the extensionmethods for the IXSocketController
interface. The following example shows server code that calls chatmessage
on all connected clients, and the client code that defines the method in a JavaScript and C# clients.
There are many extensions for both PUB/SUB and RPC, and you can of course write your own if needed.
Server
//using XSockets.Core.XSocket;
//using XSockets.Core.XSocket.Helpers;
public class Chat : XSocketController
{
public void ChatMessage(string message)
{
this.InvokeToAll(message,"chatmessage");
}
}
Client - JavaScript
conn.controller('chat').chatmessage = function(data){
console.log(data);
};
Client - C#
conn.Controller("chat").On<string>("chatmessage", data => Console.WriteLine(data));
You can specify complex types and arrays for the parameters. The following example passes a complex type to the client in a method parameter.
Server code that calls a client method using a complex object
//using XSockets.Core.XSocket;
//using XSockets.Core.XSocket.Helpers;
public void ChatMessage(string message)
{
this.InvokeToAll(new {Text=message},"chatmessage");
}
We use an anonymous "complex" object here, but you can of course create custom models (classes) as well.
Client - JavaScript
conn.controller('chat').chatmessage = function(data){
console.log(data.Text);
};
Client - C#
conn.Controller("chat").On<dynamic>("chatmessage", data => Console.WriteLine(data.Text));
Above we get a dynamic, but we can of course use any type to get the message deserialized into the correct type and get intellisense. Which is prefered
####How to hide methods and properties
You might not wanna expose all publish methods and properties to the client API's. When you want to hide a publish method/property just decorate the method/property with the [NoEvent]
attribute. The attribute is located under XSockets.Core.Common.Socket.Event.Attributes
###How to handle errors in the Controller class Wrap you logic in a try catch block and call the HandleError method that will invoke the OnError event.
When needed you can also send the error to the ErrorInterceptors if you have implemented any.
//using XSockets.Core.Utility.MessageQueue.Interceptors;
//using XSockets.Core.XSocket;
try
{
throw new Exception("boom!");
}
catch(Exception ex)
{
this.HandleError(ex);
ErrorInterceptorsQueue.Push(ex);
}
###How to create internal (long-running) Controllers A common scenario is that you want to do something every x seconds on the server. It can be polling a legacy database etc. And then push information to clients based on criterias just as you do in any XSockets server side method.
In XSockets you can write long-running controllers. A long-running controller will be a singleton
that only executes inside of the server. Clients can´t connect to a long-running controller.
The simple sample below will send a chatmessage to all clients connected to the Chat
controller from the long-running controller. The line that will make the controller a long-running controller is [XSocketMetadata("MyLongrunningController", PluginRange.Internal)]
That tells XSockets to use the controller as a singleton and that it should be internal only.
//using XSockets.Core.XSocket;
//using XSockets.Core.XSocket.Helpers;
//using XSockets.Plugin.Framework.Attributes;
/// <summary>
/// This is a longrunning controller. This cant be connected to.
/// It is a singleton that will run inside xsockets as long as the server is alive.
/// Most common is to start a timer in it to perform some task
/// </summary>
[XSocketMetadata("MyLongrunningController", PluginRange.Internal)]
public class MyLongrunningController : XSocketController
{
private Timer timer;
public MyLongrunningController()
{
timer = new Timer(10000);
timer.Elapsed += timer_Elapsed;
timer.Start();
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
//Sending a message to all clients on the Chat controller
this.InvokeToAll<Chat>("Hello from long-running controller", "say");
}
}