Using SignalR to send Real Time Notification - asp.net

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)
{
...
}
}

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

Related

Using Akka.net with Asp.net on a Modular Monolith architecture

Iwould like to implement a rest service using Akka and Asp.net.
Following the example here
I create my AkkaService containing the FooActor ref and a controller who transform the http request to a RunProcess message which is sent to the FooActor.
[Route("api/[controller]")]
[ApiController]
public class MyController : Controller
{
private readonly ILogger<MyController> _logger;
private readonly IAkkaService Service;
public RebalancingController(ILogger<MyController> logger, IAkkaService bridge)
{
_logger = logger;
Service = bridge;
}
[HttpGet]
public async Task<ProcessTerminated> Get()
{
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(60));
return await Service.RunProcess(cts.Token);
}
}
public class AkkaService : IAkkaService, IHostedService
{
private ActorSystem ActorSystem { get; set; }
public IActorRef FooActor { get; private set; }
private readonly IServiceProvider ServiceProvider;
public AkkaService(IServiceProvider sp)
{
ServiceProvider = sp;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
var hocon = ConfigurationFactory.ParseString(await File.ReadAllTextAsync("app.conf", cancellationToken));
var bootstrap = BootstrapSetup.Create().WithConfig(hocon);
var di = DependencyResolverSetup.Create(ServiceProvider);
var actorSystemSetup = bootstrap.And(di);
ActorSystem = ActorSystem.Create("AkkaSandbox", actorSystemSetup);
// </AkkaServiceSetup>
// <ServiceProviderFor>
// props created via IServiceProvider dependency injection
var fooProps = DependencyResolver.For(ActorSystem).Props<FooActor>();
FooActor = ActorSystem.ActorOf(rebalProps.WithRouter(FromConfig.Instance), "foo");
// </ServiceProviderFor>
await Task.CompletedTask;
}
public async Task<ProcessTerminated> RunProcess(CancellationToken token)
{
return await FooActor.Ask<ProcessTerminated>(new RunProcess(), token);
}
public FooActor(IServiceProvider sp)
{
_scope = sp.CreateScope();
Receive<RunProcess>(x =>
{
var basketActor = Context.ActorOf(Props.Create<BarActor>(sp), "BarActor");
basketActor.Tell(new BarRequest());
_log.Info($"Sending a request to Bar Actor ");
});
Receive<BarResponse>(x =>
{
...... Here I need to send back a ProcessTerminated message to the controller
});
}
Now, let's imagine the FooActor send a message to the BarActor telling him to perform a given task and wait the BarResponse. How could I send back the ProcessTerminated message to the controller?
Few points to take into considerations:
I want to ensure no coupling between BarActor and FooActor.
By example, I could add the original sender ActorRef to the BarRequest and
BarResponse. But the BarActor musn't know about the fooActor and
MyController. The structure of the messages an how the barActor
respond should not be dependent of what the FooActor do with the
BarResponse.
In the example I only use BarActor, but we can imagine to have many different actors
exchanging messages before returning the final result to the controller.
Nitpick: you should use Akka.Hosting and avoid creating this mock wrapper service around the ActorSystem. That will allow you to pass in the ActorRegistry directly into your controller, which you can use to then access FooActor without the need for additional boilerplate. See "Introduction to Akka.Hosting - HOCONless, "Pit of Success" Akka.NET Runtime and Configuration" video for a fuller explanation.
Next: to send the ProcessTerminated message back to your controller you need to save the Sender (the IActorRef that points to the temporary actor created by Ask<T>, in this instance) during your Receive<RunProcess> and make sure that this value is available inside your Receive<BarResponse>.
The simple ways to accomplish that:
Store the Sender in a field on the FooActor, use behavior-switching while you wait for the BarActor to respond, and then revert back to your original behavior.
Build a Dictionary<RunProcess, IActorRef> (the key should probably actually be some unique ID shared by RunProcess and BarResponse - a "correlation id") and reply to the corresponding IActorRef stored in the dictionary when BarResponse is received. Remove the entry after processing.
Propagate the Sender in the BarRequest and BarResponse message payloads themselves.
All three of those would work. If I thought there were going to be a large number of RunProcess requests running in parallel I'd opt for option 2.
Another way of doing it is by simply forwarding the next message to the next actor. The Tell operation have a second parameter that can be used to override the message sender. If you're sure that all path has to respond back to the original Ask inside the Http controller, you can do this inside the FooActor:
Receive<RunProcess>(x =>
{
var basketActor = Context.ActorOf(Props.Create<BarActor>(sp), "BarActor");
basketActor.Tell(new BarRequest(), Sender);
_log.Info($"Sending a request to Bar Actor ");
});
This way, the original Ask actor is considered as the sender of the new BarRequest message instead of the FooActor, and if BarActor decide to reply by doing a Sender.Tell(new ProcessTerminated()). the ProcessTerminated message will be sent to the Http controller.

signlar hub method termination

I'd like to know if an Hub method called from js client is
executed completely also if client disconnected during execution
For example..
public virtual void Join(int userId)
{
using (var context = new HubConnectionContext(this, RoomId, userId))
{
T workflow = GetWorkflow(context);
workflow.OnUserJoin();
}
}
I can be sure that the Dispose Method of HubConnectionContext is called also if client disconnect during using block?

How can I use SignalR as Azure Service Bus transport?

I'm trying to find an alternative to using REST to read Azure Service Bus Topic Subscriptions from the browser. Seems like SignalR would be a natural for this but I can't seem to find anyone that has done it. I'm not talking about scale-out, just a SignalR Hub that would relay a set of Service Bus functions back and forth to the browser. I'm thinking of functions like, addReceiver(string topic, string subscriptionID);defineSubscription(string name, string subscriptionRule);deleteSubscription(string name);postMessageToTopic(string topic, string message);addReceiver would initiate an async receive on the subscription. Each time a message came available from Service Bus, a function would be called on the JS client.
Here's some code to point people in the right direction.
namespace SBTester
{
public class SBHub : Hub
{
public void AddReceiver(string topic, string subscriptionName, string subscriptionFilter)
{
string messageData;
TopicConnector.Initialize( topic,
Context.ConnectionId + "." + subscriptionName,
subscriptionFilter);
// Initiate receive loop on Service Bus
TopicConnector.SBClient.OnMessage((receivedMessage) =>
{
try
{
// Process the message
messageData = receivedMessage.GetBody<string>();
Clients.Caller.onMessage(topic, messageData);
}
catch
{
// Handle any message processing specific exceptions here
}
});
}
public void DefineSubscription(string topic, string subscriptionRule)
{
// Call Service Bus to create Subscription on the Specified topic
}
public void PostMessageToTopic(string topic, string message)
{
// Call Service Bus to send a message
Clients.All.addNewMessageToPage(topic, message);
}
}
}
From your Hub code you could directly call the Service Bus APIs to send messages or directly use Service Bus APIs from JavaScript/Browsers: http://developers.de/blogs/damir_dobric/archive/2014/03/27/microsoft-azure-service-bus-receiving-of-messages-from-queue-and-topic-with-javascript.aspx

Broadcasting message to client at scheduled time using SignalR

I want to broadcast message using SignalR from server to all clients at particular server time. This broadcast message should be automatic where all clients keep listening to server method and once we reach the scheduled time on server, server should broadcast the message.
But I don't find a way to this. I was successful by invoking from a client and broadcasting it to all clients but not automatically.
How this can be achieved.
First you need some sort of hub:
public class MyHub : Hub {}
You then can connect to this hub with clients or whatever you want to do. Then you need some type of looping class that sends to your hub (you could also do this within the hub as a static timer but we'll do this as a separate class).
public class Looper
{
public Timer Interval
public Looper(TimeSpan interval)
{
Interval = new Timer(Loop, null, TimeSpan.Zero, interval);
}
private static void Loop(object state)
{
GlobalHost.ConnectionManager.GetHubContext<ChatHub>().Clients.All.executeYourMethod();
}
}
Now we need to instantiate this class somewhere, we'll do that inside our hub as a static:
public class MyHub : Hub
{
public static Looper MyInterval = new Looper(TimeSpan.FromSeconds(1)); // Send every 1 second
}
Hope this helps!
You can just add a timer to your hub class and broadcast to each client at the required intervals.

Get names of Online users connected to a Server

I am new to asp.net. I have gone through this link which has shown how to count the online users connected to a server using asp.net. (which is working when I tried)
My question is: What should I change in that code (Global.asax) so that It shows all the names of the connected users instead of counting them.
I created a chat application which stores the name of the connected user in a variable chatUsername in js file as shown below:
js file
var chatUsername = window.prompt("Enter Username:", "");
//
chat.client.addMessage = //Function
//
chat.server.send(chatUsername);
.aspx.cs file
//Using SignalR (I think this doesnt matter)
public class Chat : Hub
{
public void Send(string from)
{
// Call the addMessage method on all clients
Clients.All.addMessage(from);
}
}
You can find my complete code here
EDIT: Please provide a simple example related only to asp.net or signalr (no other technologies like MVC)
Please help.
Edit: following code refers to SignalR v0.5, not the latest 1.0Alpha2, but I believe the reasoning is the same
To do this you need to add several steps to your SignalR connection process, both in the server and in the client:
on the server side:
on application start-up, for example, you can instantiate a static in-memory repository (can be a dictionary of ) that will serve as the user repository to store all currently connected users.
In the hub you need to handle the Disconnect event (when a user disconnects, needs to be removed from the user repository as well) and notify all other clients that this user disconnected
In the hub you need to add two new methods (the names can be whatever you want) that will help client connect to the system and get the list of currently connected users:
GetConnectedUsers() that just returns a collection of connected users
Joined() where the Hub will create a new User, using the info stored in the round-trip state (the username selected by the client) and the SignalR connection ID, and add the newly created user to the in-memory repository.
on the client side:
First you need to instantiate the javascript object that relates to your server-side hub
var chat = $.connection.chat;
chat.username = chatUsername;
Then implements all the functions that will be called by the hub and finally connect to the hub:
// Step 1: Start the connection
// Step 2: Get all currenlty connected users
// Step 3: Join to the chat and notify all the clients (me included) that there is a new user connected
$.connection.hub.start()
.done(function () {
chat.getConnectedUsers()
.done(/*display your contacts*/);
});
}).done(function () {
chat.joined();
});
});
});
If you are asking why we need to add a stage like "chat.joined()" is because in the method on the Hub that is handling the connection event, the round-trip state is not yet available, so the hub cannot retrieve the username chosen by the user.
Anyway I made a blog post to show more in detail how to create a basic SignalR chat web application using Asp.Net MVC, and it is available at:
http://thewayofcode.wordpress.com/2012/07/24/chatr-just-another-chat-application-using-signalr/
In the post you will also find a link to the github repository where the source is published.
I hope this helps.
Valerio
Apparently, you are using Signal-R - so try tracking state of online users (i.e. connected clients) in java-script itself. Use Connected/Disconnected/Reconnected server side events to broadcast to all clients - from documentation:
public class Chat : Hub
{
public override Task OnConnected()
{
return Clients.All.joined(Context.ConnectionId, DateTime.Now.ToString());
}
public override Task OnDisconnected()
{
return Clients.All.leave(Context.ConnectionId, DateTime.Now.ToString());
}
public override Task OnReconnected()
{
return Clients.All.rejoined(Context.ConnectionId, DateTime.Now.ToString());
}
}
A global server side store (for example - a static dictionary) can be used to store state against the connection id - that way, this dictionary can give you users for needed connection ids. For example,
// dis-claimer: untested code - just to give the idea/hint/outline
public class Chat : Hub
{
// change to use Concurrent Dictionary (or do thread-safe access)
static Dictionary<string, User> _users = new Dictionary<string, User>()
// call from client when it goes online
public void Join(string name)
{
var connId = this.Context.ConnectionId;
__users.Add(connId, new User(connId, name));
}
public override Task OnConnected()
{
return Clients.All.joined(_users[Context.ConnectionId], DateTime.Now.ToString());
}
public override Task OnDisconnected()
{
var user = _users[Context.ConnectionId];
_users.Remove(Context.ConnectionId);
return Clients.All.leave(user, DateTime.Now.ToString());
}
public List<User> GetUsers()
{
return _users.Values.ToList()
}
}
I think this should work for you :-
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
Application["OnlineUsers"] = 0;
List<string> list = new List<string>();
}
//First check if it is Authenticated request:-
void Session_Start(object sender, EventArgs e)
{
if(Request.IsAuthenticated)
list.Add(User.Identity.Name);
//your rest of code .......
}
list will return you all the username who are online :-

Resources