0

When the client calls a Controller, a new Thread is created, which takes a long time. The View is intimidatingly returned to the user. The user should stay informed over the progress of the work, so SignalR is used. How can send updates only to the user which called the Controller.

If I create a new Thread the HTTP Context get's lost, so I don't know how I can tell SignalR to which client it should send the information.

Stefan
  • 14,826
  • 17
  • 80
  • 143
  • There are lots of different options on this page: http://www.asp.net/signalr/overview/guide-to-the-api/hubs-api-guide-server – Luke May 28 '15 at 13:58

2 Answers2

2

When you spawn your thread you should pass to it a user identifier, and then from the thread get a hub context and call something like:

var context = GlobalHost.ConnectionManager.GetHubContext<YourHub>();
context.Clients.User(userId).whatever();

on it. By default the user id would match the user name you get from your principal before calling the thread (so your HTTP context is still valid), but you can also check the IUserIdProvider interface for alternate ways of handling it.

Wasp
  • 3,395
  • 19
  • 37
1

If nature of long running operation allows it (ie you don't need to render any view or something specific to MVC), you can just implement your "long running work" inside the hub method (always use Task<T> and await to do that) and report progress back to client as shown here. Sample code is missing client side part. For that, take a look at this SO question.

This approach has another benefit. If your controller\action performing long running operation is using ASP.NET Session (which is default behavior), no other MVC actions\requests can run on server until the long running request finishes because of the Session lock - take a look here for more details. SignalR on the other side do not use Session by default so there is one less problem to worry about...

Oh BTW: Do not create your own Threads - its very inefficient. Use ThreadPool.QueueUserWorkItem or better Task<T> API...

Community
  • 1
  • 1
Michal Levý
  • 33,064
  • 4
  • 68
  • 86
  • The OP says *When the client calls a Controller*, so the long-running work cannot happen in a hub's method, which means, no matter how you implement the task, you would have the problem of passing the user identity to it anyway and report progress from there. – Wasp May 29 '15 at 11:46
  • _long-running work cannot happen in a hub's method_ ...I don't agree. Whats the problem calling hub method **instead** of controller? Its just different way of doing things... – Michal Levý May 29 '15 at 13:54
  • I'm not saying they can't in general, I'm saying the OP describes a different scenario, where no hub is called by the client (it calls a controller), therefore *in that scenario* you cannot do any task in a hub given that no calls go to it. Of course you can change that, but that's not the question. If you change that, the whole problem goes away, but the question as it is stated does not make sense anymore (HTTP Context does not get lost, for example). – Wasp May 29 '15 at 14:11
  • I understand. Question is about how to solve problem of calling long running operation on VMC controller and use SignalR to report progress. And yours answer is perfectly correct ;) I'm just saying that **when nature of long running operation allows it** (ie you don't need to render any view or something specific to MVC), it's easier to do the work inside hub method and everything just become simpler (edited my answer to make it clear)... – Michal Levý May 29 '15 at 15:19