Triggering a long process by a user in a website - c#

I want to create a web page where users can initiate a process, this process will take several minutes to complete.
My question is:
When the user clicks on a button, should I start the process on a different thread and send him to a different page? I don't want the process to end in case he closes the window or the connection is lost.
Also how can I prevent other users from initiating this process.
I thought about putting a variable in the application state that indicates whether the process is currently running or not.
Thanks for your advices

If this is a long running process it is better be moved out to a service. In this way you can scale it horizontally. If you leave that in a web site, you will need to refactor your code once you get much load.
A service can have a queue of long-running operation requests. At a given moment the service will work on one/two/whatever item(s). Depending on what you need you can persist the result of the operation and its current status to a storage.
The presentation layer initiates action (user presses button), then it polls storage for the result, once finished it delivers the result from the storage to the user.

You could spawn a thread that is going to do the work and periodically checks whether it should still continue with his work. For the work you generate a certain ID (that you may or not couple to the user for extra security) that will be used to distinguish the work job. On the redirected page you could use some javascript to tell the server that the user is still waiting for job with ID X. Should this time-out expire you can drop the work.
Create your job with a specific ID
Share somewhere a timeout variable accessible by both the server and the job-thread
Redirect the user to the landing page, where you have javascript polling the server
for the result
Once the job completes you store the result with the id and on the next poll from
the client you can pass the information to the client.
Update: If you want only one person to activate the process then you could still use the still system if you want to keep a history of some kind. You would only need to change the landing page to always look at the latest process and prevent other from starting one if there is still a process running.
Otherwise you could do the same as in the above system but use a single store point for the process results. If the store point consists a placeholder it indicates that the process already has been started and that no-one should start a new process. The display page could then poll against this store point for the info to show the users.
In the event you want everyone to be able to see the current results while a new process is being executed use two locations to store the result, one to store the finished one and one to store the busy one.

Related

ASP Notification Mechanism

I am creating a website, where people can add each other as friend.
For example I got 2 users:
User ONE with UserID = 1
User TWO with UserID = 2
When User One adds User Two, I write this to a database, with an Integer to track the status:
0 = waiting
1 = accepted (are now friends)
If denied -> I just delete that record from the database.
When User One add User Two, I want to send a notification to User Two.
So User Two should get a notification about that User One has added him, without refreshing the page.
What can I use to create notifications after adding someone as friend?
Should I look to a kind of trigger on the database that sends something to the website after a record is added, or are there other mechanisms that you guys recommend me?
It's a ASPX website, without MVC.
The same mechanism I would like to use for a Message System.
There are 3 ways of achieving this, from simplest to most complex:
Polling
Write a javascript that calls a rest service on your site every x minutes and updates the DOM of the page
Long Polling
Similar to polling but keeping an open connection to have instant replies without waiting between polls. Requires having an api that can keep a pool of open connection and a background thread on the server that polls the database for changes, which it percolates up to the javascript if needed
Web Sockets
Upgrades the connection to a full two ways connection (websocket protocol). Similar to long polling server side.
As you can see any other option than 1. is fairly complex, but you can take a look at the SingalR library to get you started.
You can use AJAX to poll the database for such updates, AJAX is mainly used to refrain from forms submissions by acting asynchronously.
Here is a simple jQuery example of AJAX polling:
function doPoll(){
$.post('ajax/test.html', function(data) {
alert(data); // process results here
setTimeout(doPoll,5000);
});
}
Also, as Brad M commented, you can "cache" the "Friends" table into the memory and poll against it rather than the DB - It would be much faster.

Run asynchronous operation in one controller method and get that operation's result in another

I have a long running operation you might read in couple of my another questions (for your reference here is first and second).
In the beginning of whole deal, project expose a form in which user should specify all necessary information about XML file and upload XML file itself. In that method all user input data caught and went to an WCF service that handles such king of files. Controller got only task id of such processing.
Then user got redirected to progress bar page and periodically retrieves status of task completeness, refreshes the progress bar.
So here is my issue comes. When processing of XML file if over, how can I get results back and show them to user?
I know that HTTP is stateless protocol but there is cookie mechanism that could help in this situation. Of course, I may just save processing results to some temporary place, like a static class in WCF server, but there is a high load on service, so it will eat all of supplied memory.
In other words, I would like to pass task to WCF service (using netNamedPipeBinding) and receive results back as fast as it really possible. I want to escape temporary saving result to some buffer and wait until client will gather it back.
As far as I go is using temporary buffer not on service side but at client's:
using (XmlProcessingServiceClient client = new XmlProcessingServiceClient())
{
client.AnalyzeXmlAsync(new Task { fileName = filePath, id = tid });
client.AnalyzeXmlCompleted += (sender, e) =>
{
System.Web.HttpContext.Current.Application.Lock();
// here is I just use single place for all clients. I know it is not right, it is just for illustrating purposes.
System.Web.HttpContext.Current.Application["Result"] = e;
System.Web.HttpContext.Current.Application.UnLock();
};
}
I suggest you to use a SignalR hub to address your problem. You have a way to call a method on the client directly to notify the operation completed. And this happen without having to deal with the actual infrastructure trouble there is in implementing such strategies. Plus SignalR plugs easily in an asp.net MVC application.
To be honest I didn't really get the part about the wcf server and stuff, but I think I can give you more of an abstract answer. To be sure:
You have a form with some fields + file upload
The user fills in the form and supplies an XML file
You send the XML file to an WFC services which procress it
Show in the mean time a progress bar which updates
After completion show the results
If this is not want you want or this is not what your question is about you can skip my answer, otherwise read on.
Before we begin: Step 3 is a bit ambiguous: It could mean that we send the data to the service and wait for it to return the result or that we send the data to the service and we don´t wait for it to return the result.
Situation 1:
Create in a view the form with all the required fields
Create an action in your controller which handles the postback.
The action will send the data to the service and when the service returns the result, your action will render a view with the result.
On the submit button you add an javascript on click event. This will trigger an ajax call to some server side code which will return the progress.
The javascript shows some sort of status bar with the correct progress and repeats itself every x seconds
When the controller finishes it will show the result
Situation 2:
-
-
After sending the data to the service the controller shows a view with the progress bar.
We add an javascript event on document ready which checks the status of the xml file and updates a progressbar. (same as the onclick event in step 4 in situation 1)
When the progressbar reaches 100% it will redirect to a different page which shows the results
Does this answer your question?
Best regards,
BHD
netNamedPipeBinding will not work for cross-machine communication if this is what you have in mind.
If you want to host our service on IIS then you will need one of the bindings that use HTTP as their transport protocol. Have a look at the duplex services that allow both endpoints to send messages. This way the server can send messages to the client anytime it wishes to. You could created a callback interface for progress reporting. If the task is going to take a considerable amount of time to complete, then the overhead of the progress reporting through HTTP might be ok.
Also have a look at Building and Accessing Duplex Services if you want to use a duplex communication over HTTP with Silverlight (PollingDuplexHttpBinding).
Finally you could look for a Comet implementation for ASP.NET. In CodeProject you will at least a couple (CometAsync and PokeIn).
I'm not sure if this is the best solution but I was able to do something similar. This was the general setup:
Controller A initialized a new class with the parameters for the action to be performed and passed the user's session object
The new class called a method in a background thread which updated the user's session as it progressed
Controller B had json methods that when called by client side javascript, checked the user's session data and returned the latest progress.
This thread states that using the session object in such a way is bad but I'm sure you can do something similar with a thread safe storage method like sql or a temp file.

subscribing takes too long for users to wait on webpage for confirmation... solutions?

On our .NET 3.5 website in c# a user clicks submit on our webpage, they are subscribed by email address to our reports. Unfortunately, this action takes about 5 minutes and the user has to sit and wait for confirmation. What I would like to do is change it so that when they click submit, they get a pop up that says they will be notified by email when their subscription goes through, meanwhile i would queue up the subscribe action somewhere else on the server so that it doesnt exist in the web code. Can you give me some ways to do this? The basic idea is that I want to split into two different lines of execution where one will allow them to still browse our website and the other will subscribe them. I was thinking split into a new thread but I think that the web code would still have to wait for that thread to finish before they could do anything else. I'm looking for ideas, preferably something that can run on the same server. thanks!
There's many options, but the basic approach will be to decouple the site from the provider. Instead you'll write out a record saying "User X is waiting to subscribe", a seperate process will then read the record and perform the actual subscription, while marking the record as "in-progress". Once the process has complete the record will again be updated with the completed information.
You can achieve this with databases, message queues, or other approaches. But fundamentally your site will only be responsible for creating the record and checking it's status--the actual interaction with the provider will be handled separately.
If you have something that takes this long and you want to true and ensure the action goes through, then your best bet is going to be to queue it up.
Basically, when they submit the request, store that in a database table and let them move on. Meanwhile, have another process that monitors that table to process the requests. When they come in just have this second process send the request on to the part that takes 5 minutes to complete.
Once it finishes, send them a "welcome to such and such email list" message. That will serve as their confirmation that it worked.
Jeff Atwood blogged on a relevant topic here a while back. Since you are using c#, I assume you're using ASP.NET and can take advantage of the cache mechanisms to kick off a periodic worker job. On the user's request, you can persist details of the subscription to some data store. In that job, you can examine the queue to determine what subscriptions need to be created and then execute them.
https://blog.stackoverflow.com/2008/07/easy-background-tasks-in-aspnet/

How to set server controls value from thread in C# web application?

I have a long running thread in my web page on a button click event
var thread = new Thread(StartTaskMonitoring);
thread.Start();
In method 'StartTaskMonitoring' I am running a while loop which depends on boolean variable _StopMonitoring
Another button "Stop" which resets the _StopMonitoring variable which makes start button event stop.
But the problem is that when I am executing thread, I am unable to update UI – say I want to update a textbox in StartTaskMonitoring method. Or it could be a progress bar.
Already tested Updatpanel1.Update(). It doesn't help. Also cannot get sessions from the thread.
How do I achieve this? so that ui is updated.
In a web application, once the request has been completed by the server (all the data sent to the client) the server cannot change anything without some action from the client.
Code on the server has no mechanism to send additional data to the client which will change the display, the only mechanism is for the client to send a request to the server1. The client can sent requests (on a timer or in response to a user action) for data and then process the new information to update the UI (this is "AJAX").
1 In the future Web Sockets will provide an easier approach, but that still requires code on the client to process the messages from the server.
The thing with background threads is that they may run even after the HTTP request has ended and rendered the page to the user. So talking about modifying UI in threads doesn't make sense. You may checkout the following article.
If you're running a process that takes a very long time then I think that your only way forward here is to have the process run as a non-web application, preferably a service and poll it for information using AJAX calls from your web app.
You'd need to provide some control within the service in order to cope with multiple demands for processing from the same session and also what to do if the session expires before the thread has completed.

Running server-side function as browser closes

Background: I'm creating a very simple chatroom-like ASP.NET page with C# Code-Behind. The current users/chat messages are displayed in Controls located within an AJAX Update Panel, and using a Timer - they pull information from a DB every few seconds.
I'm trying to find a simple way to handle setting a User's status to "Offline" when they exit their browser as opposed to hitting the "Logoff" button. The "Offline" status is currently just a 1 char (y/n) for IsOnline.
So far I have looked into window.onbeforeunload with Javascript, setting a hidden form variable with a function on this event -> Of course the trouble is, I'd still have to test this hidden form variable in my Code-Behind somewhere to do the final Server-Side DB Query, effectively setting the User offline.
I may be completely obfusticating this likely simple problem! and of course I'd appreciate any completely different alternative suggestions.
Thanks
I suspect you are barking up the wrong tree. Remember, it is possible for the user to suddenly lose their internet connection, their browser could crash, or switch off their computer using the big red switch. There will be cases where the server simply never hears from the browser again.
The best way to do this is with a "dead man's switch." Since you said that they are pulling information from the database every few seconds, use that opportunity to store (in the database) a timestamp for the last time you heard from a given client.
Every minute or so, on the server, do a query to find clients that have not polled for a couple of minutes, and set the user offline... all on the server.
Javascript cannot be reliable, because I can close my browser by abending it.
A more reliable method might be to send periodic "hi I'm still alive" messages from the browser to the server, and have the server change the status when it stops receiving these messages.
I can only agree with Joel here. There is no reliable way for you to know when the HTTP agent wants to terminate the conversation.

Categories

Resources