How to use SignalR to notify web clients from ASP.NET MVC 3 that MSMQ tasks were completed
Asked Answered
L

1

17

How would one use SignalR to implement notifications in an .NET 4.0 system that consists of an ASP.NET MVC 3 application (which uses forms authentication), SQL Server 2008 database and an MSMQ WCF service (hosted in WAS) to process data? The runtime environment consists of IIS 7.5 running on Windows Server 2008 R2 Standard Edition.

I have only played with the samples and do not have extensive knowledge of SignalR.

Here is some background

The web application accepts data from the user and adds it to a table. It then calls an one way operation (with the database key) of the WCF service to process the data (a task). The web application returns to a page telling the user the data was submitted and they will be notified when processing is done. The user can look at an "index" page an see which tasks are completed, failed or are in progress. They can continue to submit more tasks (which is independent of previous data). They can close their browser and come back later.

The MSMQ based WCF service reads the record from the database and processes the data. This may take anything from milliseconds to several minutes. When its done processing the data, the record is updated with the corresponding status (error or fail) and results.

Most of the time, the WCF service is not performing any processing, however when it does, users generally want to know when its done as soon as possible. The user will still use other parts of the web application even if they don't have data to be processed by the WCF Service.

This is what I have done

In the primary navigation bar, I have an indicator (similar to Facebook or Google+) for the user to notify them when the status of tasks has changed. When they click on it, they get a summary of what was done and can then view the results if they wish to.

Using jQuery, I poll the server for changes. The controller action checks to see if there is any processes that were modified (completed or failed) and return them otherwise waits a couple of seconds and check again without returning to the client. In order to avoid a time out on the client, it will return after 30 seconds if there was no changes. The jQuery script waits a while and tries again.

The problems

Performance degrades with every user that views a page. There is no need for them to do anything in particular. We've noticed that memory usage of Firefox 7+ and Safari increases over time.

Using SignalR

I'm hoping that switching to SignalR can reduce polling and thus reduce resource requirements especially if nothing has changed task wise in the database. I have trouble getting the WCF service to notify clients that its done with processing a task given the fact that it uses forms based authentication.

By asking this question, I hope someone will give me better insight how they will redesign my notification scheme using SignalR, if at all.

Lunette answered 17/11, 2011 at 22:48 Comment(1)
Any suggestion for thisWhat
O
8

If I understand correctly, you need a way of associating a task to a given user/client so that you can tell the client when their task has completed.

SignalR API documentation tells me you can call JS methods for specific clients based on the client id (https://github.com/SignalR/SignalR/wiki/SignalR-Client). In theory you could do something like:

  1. Store the client id used by SignalR as part of the task metadata:
  2. Queue the task as normal.
  3. When the task is processed and de-queued:
    • Update your database with the status.
    • Using the client id stored as part of that task, use SignalR to send that client a notification:

You should be able to retrieve the connection that your client is using and send them a message:

string clientId = processedMessage.ClientId //Stored when you originally queued it.
IConnection connection = Connection.GetConnection<ProcessNotificationsConnection>();
connection.Send(clientId, "Your data was processed");

This assumes you mapped this connection and the client used that connection to start the data processing request in the first place. Your "primary navigation bar" has the JS that started the connection to the ProcessNotificationsConnection endpoint you mapped earlier.

EDIT: From https://github.com/SignalR/SignalR/wiki/Hubs

public class MyHub : Hub
{
     public void Send(string data)
     {
     // Invoke a method on the calling client
     Caller.addMessage(data);

     // Similar to above, the more verbose way
     Clients[Context.ClientId].addMessage(data);

     // Invoke addMessage on all clients in group foo
     Clients["foo"].addMessage(data);
     }
}
Octastyle answered 21/11, 2011 at 15:56 Comment(7)
The non-JS client API doesn't allow me to send a specific group or client a message. As a result, there is no value to send it to the background process. However, I do send the id back to the website, which then gets the "id" of the "owner" and sends a notification to the SignalR group with that "id". As users connect and disconnect, I add the clients to the group.Lunette
your answer worked, however, in the end I decided to drop SignalR for a custom solution that transparently supports security. Therefore, a user can only send notifications to users authorized to see such messages. That requirement was never part of the original question, so I marked yours as the answer.Lunette
@WernerStrydom Did you opt for a different library or wrote all code from scratch? Could you please shed some more light on your final implementation?Seventeenth
I'm using long polling. Many browsers have disabled HTML5 sockets so and other mechanisms (such as flash) have numerous limitations.Lunette
@WernerStrydom SignalR falls back to the best supported transport that works on the client. So you don't have to worry about what browsers support as that's handled transparently. Other than that I'm not sure what else you need.Paapanen
@dfowler Security and notifications that work in a server farm. At the time I wrote this question SignalR supported neither. There was no real benefit for me to continue to use SignalR.Lunette
No problem. Good that you did your due diligence. SignalR will continue to improve and I hope you can look at it again in the future :).Paapanen

© 2022 - 2024 — McMap. All rights reserved.