Managing state server side to be requested by a hub client - signalr

I have created a really basic hub that I get the IHubContext and call the my javascript client side method via a group so I can always push the data to the same user no matter how many diffrent connections they are on, which i pass some text to and that text is appended in a multiline textbox in the browser.
It all works really nicely. The thread will typically run long operations, often appending text reporting on the status of the operation using the hub context to call the client.
However, I wish to cater for the situation where someone would close their browser then return later the page with the textbox.
Now at the moment they would just start reciving the text from the point in the operation they connect on. How can I send a request from the client to the server to retrive all the text back from the begining of the operation?
My idea was to have a StringBuilder object that i append each line identically as the text I send to the client hub.
Then on connect of the hub call a server side function from the client which asks for the full text which can be taken from the StringBuilder object ToString();
But how can the hub know where to get the StringBuilder object from in the still executing thread?
OR
If there is a way to push it to the client instead, how can I know in the executing thread that the user has connected and send the StringBuilder ToString() to the user?
NB. I do not want to resend the full string appened every time! Only when the user has just connected and needs to catch up.
I think understanding how to do this would help understand how to deal with signalR and state on the server outside of the hub. Thank you.

Well, for starters, you should probably store this data in some kind of persistent storage (not just in an in-memory StringBuilder). Regardless of that though, what you really need to do is store the individual strings with timestamps. Then just remember the last time you saw the logical user and dump all entries since that time when they are first connecting to your Hub.
JabbR, the flagship, test bed application for SignalR, does something just like this except it just does it using message ids and asks for all message ids since the last message id the client received. Check out the Chat Hub's GetPreviousMessages for details.

Related

Timeout for broadcasting message using SignalR

I am using SignalR for the 1st time in my asp.net c# web app.
I am using HTML 5 and JavaScript for my client web page.
In essence whenever my server has an image to 'push' to my clients it does so. Sometimes this can be quite frequent.
Now, I imagine during a 'busy' period' my client(s) could be 'over-whelmed' by the data being pushed by my server?
How does my server know that the message has been recieved by my client (or not) and then proceed to send the next one?
SignalR doesn't provide a built-in way to wait for a client to receive a message. This would be very difficult to do in the general case where someone might be using Clients.All, and clients might be connecting/reconnecting/disconnecting at the time the message is sent.
However, it is possible to manually acknowledge that you have received a message on the client (perhaps by calling some hub method on the server), and then continue to send the next message once the acknowledgement (ACK) for the previous one has been received.

How to Intercept ScaleoutMessage Broadcast: (Edited: How to send message directly to ServiceBus SignalR Backplane)

I have following scenario:
User request for certain resource on server, This request is long running task and very like 2~3 seconds to 10 seconds. We issue a JobTicket to user, As our user want to wait.
On receiving request we store that request in persistence storage and issue a token to user as JobTicket (GUID).
User make connection with Hub to get information about that GUID.
In Background:
We have WAS Hosted as well as Windows Service to perform some operation on that request.
On complete, WAS Hosted/Windows Service call our Web Application that job has been completed.
From there based on job Ticket we identify which user and on its connection we let user know its job has been completed.
Now we have farm of servers, we are using Windows Server On Prem ServiceBus 1.1 which is working fine, But challenge we have is that we are not able to intercept ServiceBus based backplane message broadcast and message is going to all the client. As we have farm, user intermediately may have drop connection and connected to other server based on load balancer so we need to have scale out using Service Bus as its kind of seamless to integrate and we are also using for our internal purpose in our application so we don't want to user any other mix in complex solution.
I have tried using IHubPipelineModule but still Scale out message broadcast not passing thru that, I tried to hookup SignalR code directly and debug thru it but its taking long. I don't want to mess-up something arbitrary in actual code. As I can see that in OnReceive I can see message are coming, but not able to follow further. I just need small mechanism that I can intercept broadcast message and make sure that it goes to client it intended and not all the client by wasting resources, and security concern as well.
Please help me on this issue, it's kind of stuck from last 4 days and not able to come to any solution and same time I want to go with establish pattern and don't want to fork any special build for this kind of small issues which I am sure one of you expert knows how I can do that seamlessly.
Thanks,
Shrenik
After lots of struggling and not finding straight forward way, I have found the way as below for someone else in future it might help.
Scenario:
1. Web Farm: Host External User facing Web Pages
2. Backend Process: Which is mix of WebApi, SharePoint, Windows Service etc.
User from Web Page submit some request and get a unique id as return back. Internally on receiving request, we queue that request to Service Bus using TopicClient for processing.
There are pool of Windows Service watching on Message on Service Bus using SubscriptionClient and process that message. On completion of process which can run from 5 seconds to 30 seconds and some cases even more. We need to inform client that its job done if its waiting on web page or waiting for completion notification.
In this story, We are using SignalR to push job completion notification to client.
Now my earlier problem is How I let know from windows service to web application that job is done so send notification to client who submitted request.
One way is we hosted another hub internally in web application, Windows service act as client and call web application hosted hub, and in that hub method it will call external facing hub method to propagate message to specific client who submitted request, for which we are using Single user Group.
And as we have register service bus as backplane it will propagate to other servers and then appropriate client will get notification. So this is ideal solution and should work in most cases.
In above approach we have one limitation that, how Windows Service connect to Web Client, as we donot have windows auth, but we have openid based auth with ADFS. Now in such case Web Application required special code in which provide separate userid or password for windows service to communicate or have windows authentication also allowed for that hub for service account of windows service.
I was trying and trying how to remove all this hopes between interserver communication and again management of extra security.
So I did below with simplicity, though it tooks me whole night to find our internal of SignalR. But it works:
Approach is to send message directly to ServiceBus Backplane, and as all Web Server already hooked-up with ServiceBus backplane then they will get message.
Unfortunately SignalR doesn't provide such mechanism to send message directly to Backplane. I think its on pub/sub model so they don't want somebody to hack in their system :). or its violation of their pattern, but its make sense, in my case because of different roles and security, I have simplify code as below:
Create a ServiceBusMessageBus instance in my code, Same way as Below: Though I have created separate instance and store till lifetime of Windows Service, so I don't create instance every time:
ServiceBusMessageBus serviceBusBackplane = new ServiceBusMessageBus(new DefaultDependencyResolver(), new ServiceBusScaleoutConfiguration(connectionString, appName));
Create a ClientHubInvocation Object: This is a message which actually get created in SignalR infrastructure when Backplane based message broadcast:
ClientHubInvocation hubData = new ClientHubInvocation
{
Args = new object[] { msg },
Hub = "JobStatusHub",
Method = "onJobStatus",
State = null,
};
Create a Message object which accept by ServiceBusMessageBus.Publish, Yes, so this is a method which actually get called on base class ScaleoutMessageBus.Publish. This class is actually responsible for sending message to topic and other subscribers on other server nodes. Why not use that directly. Now to create Message Object, You need following code:
Message backplaneMessage = new Message(
sourceId,
"hg-JobStatusHub." + name,
new ArraySegment(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(hubData))));
In above second parameter is something interesting,
In case if you want to publish to all the client then syntax is "h-", in my case specific group user, so syntax is "hg-.. You can check the code here: https://github.com/SignalR/SignalR/blob/bc9412bcab0f5ef097c7dc919e3ea1b37fc8718c/src/Microsoft.AspNet.SignalR.Core/Infrastructure/PrefixHelper.cs
Publish your message to backplane directly as below:
await serviceBusBackplane.Publish(backplaneMessage);
I wish this PrefixHelper class have been public.
Remember: This is not recommended way and doent insulate from future upgrade for SignalR, as its internal they may change so any upgrade might come with small hazale to change this code. But in summary this works. Hope SignalR Team provide some mechanisam out of box to send message directly to backplane instead.
Thanks

Implementing a robust and efficient RPC system

I need to have a server which is able to call functions on the client. I always used RPC's in different networking game API's but I never implemented it by myself.
How would I do it?
My naive approach would be:
connect client to the server:
server
fn update_position_client(){
unique_id = 1;
send.to_client(unique_id);
}
client
while recv_messages {
if id == 1
update_position();
}
Is this how I would do it?
This works if you only have a few messages that you want to send, and if the data basically known. To be more robust, you would want to have the ability to dynamically add/remove messages that can be called, and figure out how to look up the methods to be called when RPC is called.
Assuming you want this to be completely transparent to the user, what typically happens in this case is that when the a message is sent, the RPC library will wait until there's a response back. Assuming bi-directional capabilities, what normally happens is that there's a single thread that listens for data. If an RPC message comes in, this thread will figure out what to do with the message, i.e. what method to call in your(local) address space and with what parameters you want to call it with. When you send an RPC message out, the thread that you sent the message out on is blocked(probably with a semaphore) until the return message comes back, at which point your local thread is unblocked and allowed to continue.
A Linux-specific RPC library you could look at would be DBus.

C# TCP Multithread Server and Client with requirements

I am currently working on TCP multithread server and clients written in C#. I was looking around on Google and tried more than 5 examples but seems none of them can serve all requirements. As I am not familiar with networking, so it would be appreciated if someone can point me to the right direction.
Here are the requirements I need:
multithread, I need a server which can handle multiple clients, though those clients do not need to communicate each other.
continous operations, after clients connected to the server, they need to keep sending messages to each other, until the server drops all the clients. The server needs to identify each client. The clients do not need to disconnect from server on themselves, normally.
disconnection notification, most of those examples found on Google do not have this feature, I need the server to know when the connected client disconnects, so the server can notifiy the user.
Actually the closest example I found is this:
http://www.codeproject.com/Articles/22918/How-To-Use-the-SocketAsyncEventArgs-Class
But the problem I am facing is that the messages are inside the class Token, I included all those classes in my Window Form Application, which is my main application. Those information like client ID, client status, or actions to clients, will be performed in the Form. I dont know how to bring those variables from Token class to my Form.
This is another example seems can suit my purpose:
http://www.codeproject.com/Articles/2866/Multi-threaded-NET-TCP-Server-Examples
But I am not sure how to change it since it blocked my Form from displaying.
Thanks for help.
Some months later... First, you have to keep in mind that the window form isn't async native, you have to implement invoke methods to use the tcp AsyncCallback. Elsewhere to handle clients, you have to create a new dictionary like :
Dictionary<string, System.Net.Sockets> clientList;
It could be int in case of database ids or simply you could use the native system handle :
this.anonymousSock.Client.Handle
And adding them like this :
clientList.Add("ID", this.anonymousSock);
Finaly :
public void Send(string data, string id)
{
Socket Client = this.clientList[id];
byte[] byteData = Encoding.ASCII.GetBytes(data);
Client.BeginSend(byteData, 0,
byteData.Length, 0,
new AsyncCallback(SendCallback), Client);
}
While receiving, you could in this case identify client by checking your sockets entries or by using tokens.
And then no cpu/memory burn with threads.

.NET page caching but still receive query string

Is it possible to cache a page render on an iis web server, but still receive and write query string values (that don't affect output) to the database? So that the page render does not have to wait for the database trip to execute in order to serve the page? If possible, how do I implement?
For example, we track various affiliate and search marketing data via query strings, and in the master page code behind, we write the given query string data to the database. The output of the page doesn't change at all for the user (however we may set a cookie based off the qs parameter).
My understanding is that the page render has to wait for the database trip to fully execute in order to render the page. Is that even true?
Yes in general though it can depend on how one handles the caching.
First, you should move that tracking stuff to where it belongs -- a HttpModule. Page need not concern itself. Second, what you probably want to look into is some sort of fire and forget service call or message queueing. This makes the database write a non-blocking operation rather than a blocking operation.
Some options for making the operation non-blocking:
if you are actually writing to a web service, there is an underappreciated [OperationContract(IsOneWay = true)] decoration. Tells the generated proxy to fire and forget the call, will not wait for a response.
Another option would be to use the Asynchronous ADO.NET bits, especially BeginExecuteNonQuery. If you don't handle the callback this should just execute off your thread.
You could always just spawn a thread and deal with it in a non-blocking manner yourself. Just be real careful about handling errors on this thread -- unhandled exceptions will take out the app domain.

Resources