Setting state variables on the client side in SignalR - c#

I'm using the javascript library to connect to a signalR server being hosted in a console app.
Therefore I connect and set client methods which can be called from the server like so:
var connection = $.hubConnection('http://localhost:8080'),
proxy = connection.createHubProxy('TestApp');
proxy.on('sendMessage', function () {
// do stuff!
});
which is described in detail here.
However, the documentation for using the client side javascript in this manner doesn't explain how to round-trip information (set the 'state' variable on the client side and have it accessible from the server).
It's probably pretty obvious, but any help will be much appreciated!
Also, there is something which I think is closely related that I'm curious about. I know the client side code can get a return value/callback after calling a function on the server like so (from the documentation linked above)
proxy.invoke('add', 1, 2)
.done(function(result) {
console.log('The result is ' + result);
});
but is it possible for the server to get a callback from the client when the client finished a task? (Obviously just having a the client trigger a predefined event solves this problem, but it would be nice to handle all callback without having to setup another event if this is possible.)
Thanks!!

1)
For setting state it's as simple as:
proxy.state.foo = 1337;
Then of course you can get this on the server via
int myFoo = Clients.Caller.foo;
2)
No you are unable to be notified on the server when a client side function has finished executing. If you're trying to know when a client side function has finished you can simply call back to the server yourself.
For instance:
proxy.on('foo', function(){
console.log("Foo executed");
proxy.invoke("fooDone");
});
You'd then need to create a "fooDone" function on the server to handle the callback.
Hope this helps!

Related

Server function to be ran once for all users

Good evening,
In my SignalR application I have a javascript timer that is ran for all users "simultaneously". At the end of this timer, a server function is called, and this is where this problem starts.
As the function is called at the end of the timer, every connected user calls it at the same time, which is unnecessary because it will return the same output for all connected users. Being a logically complex function, having the server run it unnecessarily for all users adds up to be a great resource waste.
How can I make it so that it is ran only once (maybe the first time it is called (until the next timer stops))?
Thank you in advance
You could make use of GlobalHost.ConnectionManager.GetHubContext. This will allow you to get any hub context and then trigger Clients.All.YourFunction on that context. That will send send a message to all connected clients subscribed to that hub.
You will need to have a background process that runs every at the time your JavaScript function fires (by the way, relying on all your clients to call a JavaScript function simultaneously is really not a good idea; different client locations and different machine performance will mean they're not likely to be simultaneous).
The following is assuming that you're just running this on a single server. If you're going to be deploying this to a web farm, then you'll need to use a Database value to ensure you don't repeat the same work, or set up a particular server instance to be responsible for doing the calls (otherwise you'll end up with one call per server).
Create a process that runs in the Background (I'm sticking with a simple thread here, I actually use HangFire for this, but this will suffice for the example), e.g. On App_Start
Thread thread = new Thread(new ThreadStart(YourFunction));
thread.Start();
Then create YourFunction which will be responsible for your client calls:
private bool Cancel = false;
private void YourFunction()
{
do
{
string foo = "Foo";
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<YourHub>();
context.Clients.All.SendYourMessage(foo);
Thread.Sleep(10000);
}
while(!Cancel)
}
And then on the client, just handle the message from the hub:
youyHub.client.sendYourMessage = function(message)
{
// message == "Foo"
};

Can my socket server routine work?

I'm trying to build multiple client - one server structure. Each client makes connection to server and server maintains those connection.
Client have two thread(thread1, thread2) running asynchronously and sharing 1 socket to send, receive. Two thread each contain multiple send, receive function. For server to serve each client, it also have to make two client handler that share 1 socket.
I wanna have my server to create client handler routine(asynchronous task) only when their(each client) socket is ready-to-read to save resource. I'm trying to implement this feature using 'Socket.Select' method.
Here's my assumed implementation of server side select routine using code close to c#.
server.selectRoutine(){
while(!serverSocket.closed())
{
checkReadList client_connect_socket_list_copy=new ArrayList<Socket>(client_connect_socket_list) ;
Socket.Select(client_connect_socket_list_copy, null,null) ;
foreach(Socket s in client_connect_socket_list_copy)
{
client_connect_info info=client_connect_info_dict.Items[s] ;
if(!info.is_client_thread1_handler_active)
{
info.is_client_thread1_active=true ;
clServerEntranceHandler handler=new clServerEntranceHandler() ;
Task.Run(handler.run()) ;
}
if(!info.is_client_thread2_handler_active)
{
info.is_client_thread2_active=true ;
clServerExitHandler handler=new clServerExitHandler() ;
Task.Run(handler.run()) ;
}
}
Code Explanation
Client_connect_socket_list: contains currently connected clients
client_connect_info_dict: client connect info dictionary mapped for each socket as key.
client_connect_info: consist of (is_client_thread1_Handler_Active, is_client_thread2_Handler_Active)
Select only those sockets that are ready to be read after Socket.Select
Run handler for those sockets where handler is currently not made, info.is_client_thread1_Handler_Active=false. And set info.is_client_thread1_Handler_Active=true. This is because there will be multiple recv function inside already-made handler and they are in blocking mode. So when client sends message to server destined to recv function blocked in already-made handler, Socket.Select will also think this socket as ready-to-read and it will end up creating new handler. To avoid this, i need to check whether handler is active. After handler finishes, it will set info.is_client_thread1_Handler_Active= false inside. Same for client_thread2 handler.
I think i now have to synchronize this routine with each handler already made. For example, avoid situation like recv function inside handler P snatch message A inside message queue of handler P's socket after Socket.Select saw message A inside message queue. Then handler P will end and set info.is_Handler_Active=false. Then selectRoutine will create new handler again for message A already read by handler P and there goes trouble.
I wanna know whether there is serious problem with this scheme that i should not use it. And if there is, then i wanna know better ways to implement multiple client - one server with room for scaling.

ZeroMq recv not blocking

I'm attempting to learn ZeroMq for project at work although my background is in C#, and in the most simplest of tests I seem to have an issue where the socket.recv(...) call will block for the first received message, but after this throws an exception because the amount of data received is -1.
Currently my 'server' is:
zmq::context_t context(1);
zmq::socket_t socket(context, ZMQ_REP);
socket.bind("tcp://127.0.0.1:5555");
while (true)
{
zmq::message_t message;
if (socket.recv(&message))
{
auto str = std::string(static_cast<char*>(message.data()), message.size());
printf("Receieved: %s\n", str.c_str());
}
}
This is basically from following the first example server within the ZeroMq documentation.
I'm pushing 1 bit of data from a C# 'client' using this code:
using (var context = new ZContext())
using (var requester = new ZSocket(context, ZSocketType.REQ))
{
requester.Connect(#"tcp://127.0.0.1:5555");
requester.Send(new ZFrame(#"hello"));
requester.Disconnect(#"tcp://127.0.0.1:5555");
}
Now I start the server, then start the client. I correctly receive the first message and I am correctly able to print this.
But now when I hit socket.recv(&message) again the code won't block but will instead throw an exception because the underlying zmq_msg_recv(...) returns a value of -1.
I'm unsure why this is occurring, I cannot see why it is expecting another message as I know that there is nothing else on this port. The only thing I came across is calling zmq_msg_close(...) but this should be called as part of the message_t destructor, which I have confirmed.
Is there anything I'm doing wrong in terms of the socket setup or how I'm using it for the recv(...) call to stop blocking?
Your problem is that you cannot receive 2 requests in a row with the REQ-REP pattern.
In the Request-Reply Pattern each request demands a reply. Your client needs to block until it receives a reply to its first request. Also, your server needs to reply to the requests before it services a new request.
Here is a quote referring to your exact issue from the guide.
The REQ-REP socket pair is in lockstep. The client issues zmq_send()
and then zmq_recv(), in a loop (or once if that's all it needs). Doing
any other sequence (e.g., sending two messages in a row) will result
in a return code of -1 from the send or recv call. Similarly, the
service issues zmq_recv() and then zmq_send() in that order, as often
as it needs to.

How to call a script with SignalR when item created to DB

I'm newbie with SignalR and want to learn so much. i already read beginner documents. But in this case i've stucked. what i want to do is when a user got new message i want to fire a script, like alert or showing div like "you have new mail" for notify the recieved user. And my question is how can i do that ? is there anyone know how to achieve this ? or good "step-by-step" document? i really want to work with SignalR.
ps: i'm using Visual Studio 2012 and MsSQL server
edit: i forgot to write, notification must be fired when message created to DB
Thank you
In your Scripts use the following, naturally this is not all the code, but enough based off tutorials to get you going. Your userId will be generated server side, and somehow your script can get it off an element of the page, or whatever method you want. It runs when the connection is started and then every 10 seconds. Pinging our server side method of CheckMessage() .
This js would need refactoring but should give you the general idea.
...
var messageHub = $.connection.messageHub;
var userId = 4;
$.connection.hub.start().done(function () {
StartCheck();
}
//Runs every 10 seconds..
function StartCheck()
{
setInterval(messageHub.server.checkMessage(userId,$.connection.hub.id), 10000);
}
This method takes in a userId, assuming your db is set up that way, and grabs them all from your database; naturally the method used is probably not appropriate for your system, however change it as you need to. It also checks if the user has any messages, and if so sends down another message to our SignalR scripts.
public void CheckMessage(int userId,int connectionId)
{
var user = userRepo.RetrieveAllUsers.FirstOrDefault(u=>u.id == userId);
if(user.HasMessages)
{
Clients.Group(connectionId).DisplayMailPopUp();
}
}
Finally this message, upon being called would run your code to do the 'You have Mail alert' - be it a popup, a div being faded in or whatever.
...
messageHub.client.displayMailPopUp = function () {
alert("You have Mail!");
};
...
Hopefully this helps - I recommend the following links for reading up and building your first SignalR app:
http://www.asp.net/signalr/overview/signalr-20/getting-started-with-signalr-20/tutorial-getting-started-with-signalr-20-and-mvc-5
And a smaller sample: http://code.msdn.microsoft.com/SignalR-Getting-Started-b9d18aa9

C# Multithreading ASP .NET MVC 4 - Equivalent of System.Windows.Threading.Dispatcher?

I study .NET and now i'm learning web developement with ASP .NET MVC 4.
I made a Task :
Task t = new Task(new Action(() =>
{
while (convert("suitandtie.mp4") != 1)
{
if (i == 4)
{
// Here I want to access in mainthread property
// I need to change text for viewBag like :
// ViewBag.Message = "Convert failed";
// But I need a Dispatcher and invoke for accessing
// the ViewBag of the mainthread
break;
}
i++;
}
}));
t.Start();
In .Net Application, With System.Windows.Threading.Dispatcher, it's possible to use it for call invoke.
I did that in my application :
this.Dispatcher.Invoke(new Action(() =>
{
ContactBook.Add(Person("Mark", "232 521 424"));
}));
When I added Mark in contact book, it added in the ContactBook of the mainthread, not of the thread created by Task.
Help please for accessing ViewBag.Message of the mainthread?
Why do you need to create that as a separated thread?
I am asking because unless the client is making aysn calls, there is no benefit in doing that, granted that you are not going to be doing many things at the same time and deferring the execution of the controller to some other service.
The easiest way if your you to pass in the current Thread to the ViewBag thought.
There is no mapping. There is no means of interacting with the response because the response has [potentially] already been sent and the connection closed at that point in time.
If you start an asynchronous operation and don't have something in the request's context blocking on that operation then that async operation can't interact with the response at all.
The best that you'll be able to do is store the results of anything you generate in some external storage mechanism (such as a database) so that a future request from the server can get the information and send it to the client.
The Viewbag (and any page state) is only available before the response was sent to the client. It's the way the classic webserver model works: The client request an URL, the server answers something (HTML, javascript, octet Stream...) If your operation is a few minutes long, you should consider using something slightly different.
Personnaly, I would load the initial page with a classical ASP.NET MVC action, then starting the long duration task through a subsequent javascript request.
To run the task, use something like SignalR, which will enable you to perfom duplex communications between your client and your server. With SignalR, the server will be able to notify the client at the end of the task rather easily. And it's very easy to use in an ASP.NET MVC app.

Categories

Resources