Billy Billy - 2 months ago 38
ASP.NET (C#) Question

Using SignalR to send Real Time Notification

I want to create a new system to send real time trade execution messages to users using SignalR. In the old system, each client connects to the trading server using Java Applet TCP connection.

I use the following tutorial as reference
http://www.asp.net/signalr/overview/getting-started/tutorial-server-broadcast-with-signalr

There is a line of code in the StockTicker constructor to update the stock prices:

_timer = new Timer(UpdateStockPrices, null, _updateInterval, _updateInterval);


However, I need to update trade execution in real time instead of updating stock prices per 250ms.
Is it okay to create TCP connection to my trading server per client in the constructor? It seems that in the sample code, the constructor of StockTicker (i.e. my TradingManager) will be called one time only. But in my design, I want to create a TCP connection per client. How should I change the code to do this?

Here is my code:

TradingHub.cs

public class TradingHub : Hub
{
private readonly TradingManager _tradingManager;
public TradingHub() : this(TradingManager.Instance) { }

public TradingHub(TradingManager tradingManager)
{
_tradingManager = tradingManager;
}
...
}


TradingManager.cs

public class TradingManager
{
// Singleton instance
private readonly static Lazy<TradingManager> _instance = new Lazy<TradingManager>(
() => new TradingManager());

...

public static TradingManager Instance{ get{ return _instance.Value; } }

public TradingManager()
{
...
this.apiConnector.MessageReceived += new CustomEventHandler(this.api_MessageReceived);
init();
}

private IHubConnectionContext<dynamic> Clients { get; set; }

private void init()
{
TradingSession tradingSession = getLoginSession(user);

// connect to trading server using TCP connection
this.apiConnector.ensureConnected(host, port, tradingSession);

// send keep alive message to trading server periodically
_timer = new Timer(sendKeepAlive, null, _updateInterval, _updateInterval);
}

private void api_MessageReceived(object sender, CustomEventArgs e)
{
// when web server receives trade execution from server, send out the message immediately
Clients.Caller.SendTradeExecutionMessage(......);
}

public static TradingSession getLoginSession(string user)
{
...
}

private void sendKeepAlive(object state)
{
...
}
}

Answer

If you were to make a new TradingManager in your Hub constructor instead of referencing a singleton, you would be creating more than one TradingManager per SignalR connection. Hubs are reinstantiated per method call. Every time you invoke a hub method or a hub event is called (e.g. OnConnected, OnReconnected, OnDisconnected), your constructor will be called.

However, OnConnected is only called once per SignalR connection. By the way, SignalR connections are completely orthogonal to TCP connections. With the long polling transport, for example, a new HTTP request is sent each time a message is received.

I think you want to create a new TradingManager instance each time OnConnected is called and potentially associate it with the client's Context.ConnectionId and store it (perhaps in a ConcurrentDictionary) so you can retrieve it using the connection id when your Hub methods are called. You can then dereference the stored TradingManager instance for a given connection id in OnDisconnected.

You can learn more about SignalR connections at:

http://www.asp.net/signalr/overview/guide-to-the-api/handling-connection-lifetime-events

You can learn more about the Hub API and the On* methods at:

http://www.asp.net/signalr/overview/guide-to-the-api/hubs-api-guide-server#connectionlifetime

Comments