Just 10 short months ago, I wrote a blog post about how to kick off a long-running process from a web page. It used jQuery to talk to an ASMX web service, and polled for the status every second.
Since then, I’ve learned a lot of new things. So, I took a look at that project and went to see how I would approach this now, with newer technologies.
OPTION 1 – The Original – jQuery + ASMX (SederSoftware.Worker.WebUI):
Just to recap, this first approach I initially did was inspired from work. I was working with a developer and we were limited on what technologies we could use for that project. So, the sample lets you kick off a long-running process in another thread and that process reports back status. jQuery on the client-side would poll once-per-second to get the latest status.
Why is this bad?
Well, it’s not bad, but it could be much better. It’s not ideal because the client-side is only getting updates when polling. This is inefficient and plus the UI only updates once per second. It would be better for the server to simply tell us when there is an update.
Also, ASMX services are limited. It’s much simpler to use WebAPI or SignalR for the backend nowadays.
OPTION 2 – SignalR (SederSoftware.Worker.WebUISignalR):
The next approach was to create a simple MVC project. In there, a single view would reach out to a SignalR service to kick off the process – and then wire up an event handler for when the server is to report back status.
If you are not familiar, SignalR is a pretty amazing component. It figures out the best form of communication between the client and the server. if you are using a modern browser though, chances are you’re connecting to a websocket for updates, which is very efficient.
This approach gives a MUCH better user experience with immediately and smooth updates, and requires less-code. One gotcha to getting SignalR working is two things:
Thing 1) In App_Start, create a Startup.cs file that looks like this:
Thing 2) In your PropertiesAssemblyInfo.cs file, add an entry like this:
This are both needed to get SignalR working – and that wasn’t obvious to find, so I thought I’d write it down!
OPTION 3 – SignalR + AngularJS (SederSoftware.Worker.WebUIAngularSignalR):
Now that we have SIgnalR working, what about adding an AngularJS front-end to it. How DO you have AngularJS interact with SignalR? Well, first a best-practice is to create a “service” in Angular, that is a module that you can use from controllers. The tricky part though which stopped me dead-in-my-tracks was: “How do I publish the event I receive from the server, to my consumer?”. I wasn’t even sure how I wanted that to work, never mind how to implement it.
In other words, any Angular controller who uses this service can start the long-running process by binding to “startProcess”. Then, that controller can receive the updates by using $on like this:
OK, it’s not a lot of code, but it can be a little confusing if you are not familiar with Angular. Why did we go through all of this? Well first, I’m working on a project at work that requires this, so I thought I’d figure it out. Also, the UI is even cleaner than before – this is the HTML for this process:
One more REALLY cool benefit of using Angular like this? Since all of the routing is done client-side, I can click on other links in my site – and when I come back to the “page” with the long-running task, it is still in the same state – showing me status, and updating! I thought that was pretty cool.
The point of all of this is simply to document some options. Here was have 3 different ways to kick off a long-running process on the web server and show rich feedback as to the status. Again, you can view the source of each of these or pull down the source from this sample repository. Let me know if you have any questions or have any ideas of better ways to do this.