Starting a new thread on a web page button click - c#

I have inherited a legacy app and there is some code that can be simplified down to:
protected void SomeButton_Click(object sender, EventArgs e)
{
var otherThread = new System.Threading.Thread(delegate()
{
System.Threading.Thread.Sleep(20000);
FireAnAsyncProcess();
});
otherThread.Start();
thankYouPanel.Visible = true;
otherPanel.Visible = false;
}
The FireAnAsyncProcess() seems to be intermittently failing to run. This could of course be a number of things but I wondered:
Given the pause of 20000 above, will FireAnAsyncProcess() always be called even after the button click has been handled? Does the new thread get called regardless of what happens to the thread that called it?
Edit: the result/outcome of FireAnAsyncProcess() is not required on the web page and the page is not intending to wait for them. Rather it is trying to start the thread and assume it gets fired.

This is web environment - each request is handled in their own thread context, and the Thread.Start() isn't useful: the child thread will be aborted after the request been handled, and the parent thread aborted.
So if you need to run some piece of work on Button_Click, you should host a WCF service or Windows Service or something being able to accept some message from web-application and run the job in background.

Related

Improving user experience in Windows Forms Client that has low internet speed and uses a WCF web-service hosted far away

I have a live WCF service hosted in US. I want to access it from a Windows Forms application that can be used from anywhere in the whole world. Currently I am testing it in India and trying to access my US hosted web-service. This application can be used from any connection speed and at any distance from the server. So speed of response from the server may vary. What I decided is that when user performs some function, my application will first update the UI and then it will perform the server update task in background. This will prevent the application from freezing or hanging. Following is one of these scenarios. But the problem is that even I am using Asynchronous functions and threads to update UI and server, the application is still freezing.
Actually I have a button that acts as a toggle between like and unlike. When a user clicks it, it should change to unlike and then it runs a thread that updates the server in background. Following is the code for the Button's click event:
async private void btnLike_Click(object sender, EventArgs e)
{
new System.Threading.Thread(new System.Threading.ThreadStart(changeLike)).Start();
await LikeContent();
}
changeLike function:
private void changeLike()
{
if(btnLike.Text.Equals("Like"))
btnLike.Text="Unlike";
else
btnLike.Text="Like";
}
LikeContent function:
async Task<int> LikeContent()
{
await Global.getServiceClient().addContentLikeAsync(cid, uid);
System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(reloadLikes));
t.Start();
return 0;
}
addContentLikeAsync() function is a WCF web-service function that updates user likes on server.
reloadLikes() updates the number of likes from the server after user liked the content.
Please tell me how can I modify my code so that application instantly updates the LIKE button instead of freezing for some time and then updating the LIKE button? Because this "sometime" will create a bad impression on users having less internet speed.
First, I assume the btnLike_Click method is called on the UI thread. In this case, do not call changeLike() on a separate thread.
async private void btnLike_Click(object sender, EventArgs e)
{
changeLike();
await LikeContent();
}
Second, be sure to marshal back to the UI thread before reloadLikes()
async Task<int> LikeContent()
{
await Global.getServiceClient().addContentLikeAsync(cid, uid);
// Ensures this occurs on the UI thread - WinForms
Invoke((Action)reloadLikes);
return 0;
}

Silverlight What should a worker thread do after finish work?

So here is my problem with my Windows Phone application.
I have Page 1 that can navigate to Page 2. In Page 2 OnNavigateTo I make a async call.
This seems ok the first time I run the application, the async call creates a new worker thread and does work for me which is cool. But I realize that if I go back to Page 1 and re-invoke Page 2 the problem appears: Now I have a new worker thread from the async call while the old one was not terminated. So there is a race between the two worker threads and cause a problem to my application. I don't have direct control to the threads since they are implicitly created by async methods.
So in this case, anyone has suggestion on how to deal with it or is there a common pattern of dealing with this issue?
It depends on how you're issuing the async request. If you're using say, WebClient to do something like DownloadStringAsync you'll see that your WebClient instance has a method CancelAsync that will set the cancelled property in your Completed event handler to true. Just call CancelAsync when you leave your page and test for this in your handler and you should be good.
// in some button handler or whereever
webClient.DownloadStringAsync("http://url.com")
void OnLeavePage(object sender, EventArgs e) {
webClient.CancelAsync();
}
void OnCompleted(object sender, DownloadStringCompletedEventArgs e) {
if (e.Cancelled) {
return;
}
// do your handling
}
If you don't have CancelAsync you can pass in a UserState object that has a Cancelled property to emulate the behaviour (set it to true when you leave and test in your handler).

App for monitoring changes

I am writing a GUI app for monitoring and I'd like to get some advice on it's logic. Basically all the app needs to do is connect to a distant server every x minutes, check if something was changed, get changes if any, act upon them (update local db and so on, depending on changes).
My first idea was:
Have a checkbox (monitoring on/off). On click (if checked) starts a Timer.
Timer launches a BackgroundWorker in it's Tick method.
DoWork method does the connecting / retrieving info stuff
a) on WorkDone handler method gets the info from background worker and does local updates with it
b) on WorkDone handler method triggers one or more of custom events "SomethingChanged" depending on changes it got; EventListeners handle local updates from there.
My main problem is calling Worker from Timer since I added Worker to the Form and now they are on different threads (is that correct description?) and then passing results around is a similar problem. I was reading about delegates but still not sure what to use when and how, and if it's really necessary in the first place. Do I need both bgWorker and Timer? Do I need custom events or can I just do all work inside workDone with Switch(result)? Is this general principle good in the first place, maybe there's something better and I am reinventing the wheel? Thank you in advance!
From an architecture point of view:
Message Queues decouple bits of your application. You can in Windows Forms applications rely on the Message Queue that Windows creates and manages for you. Google for PostMessage/GetMessage etc. This is generally called "message passing".
Typical Arcitecture
One part of your app "pushes" a request into a queue
Some other part of your app "pulls" a request from a queue and writes a result to a second queue.
The first part can then "pull" requests from the second "results" queue and display to a user.
So it looks like this:
App --> REQUESTS QUEUE --> processing engine --> RESULTS QUEUE --> App
The processing engine could be in the same app, on the same thread or in a different thread/process (or even different machine).
You can use simple queues : say a Queue<string>() (as long as you use locks to access it) or increase complexity or more and more complex/functional queues.
Issues with the naive strategy and other solutions ... things to think about:
What happens if you make a new request while the old one has not yet completed?
What happens if an error occurs? Do you want errors inline? You can use another queue for errors?
Do you want retries?
What happens if a message is lost? (i.e. a request was pushed, but no response comes in...)? There are transactional queues etc.
Sample Code
object oLock = new object();
Queue<string> requests = new Queue<string>();
Queue<string> responses = new Queue<string>();
Thread mThread;
AutoResetEvent mEvent = new AutoResetEvent(false);
public Form1()
{
InitializeComponent();
mThread = new Thread(ProcessingEngine);
mThread.IsBackground = true;
mThread.Start();
}
private void ProcessingEngine()
{
string result;
string request = null;
while (true)
{
try
{
mEvent.WaitOne();
lock (oLock)
{
request = requests.Dequeue();
}
var wc = new WebClient();
result = wc.DownloadString(request);
lock (oLock)
{
responses.Enqueue(result);
}
}
catch (Exception ex)
{
lock (oLock)
{
responses.Enqueue(ex.ToString());
}
}
}
}
private void timer1_Tick(object sender, EventArgs e)
{
lock (oLock)
{
//Stick in a new request
requests.Enqueue("http://yahoo.com");
//Allow thread to start work
mEvent.Set();
//Check if a response has arrived
if (responses.Any())
{
var result = responses.Dequeue();
listBox1.Items.Add(result.Substring(1,200));
}
}
}
}
If you use System.Windows.Forms.Timer instead of System.Threading.Timer, your Tick handler will be called from Form's message loop and you'll have full access to all controls - it will be safe to call bgWorker.RunWorkerAsync(). As for retrieving results - RunWorkerCompleted is also called from message loop thread and you can safetly update your UI here.
The solution is simple - INVOKE back into the main thread. THere is an Invoke method on the winform control. This will basically change threads for execution to the UI thread, and allow you to manipulate the UI.
Do that "block" (i.e. not once per control but once when you have news).

C# Timers stopping intermittently

Can anybody suggest any reasons why a C# timer (created in a code-behind class) would stop without being told to?
My timer starts on page load and then stops when I click a button. I don't need to click the button for it to sometimes stop. IIS is not being restarted to my knowledge and no errors are being thrown either.
This is confusing me quite a bit...
Thanks.
// This gets called on page_load
private void checkTimer()
{
if (!parentTimer.Enabled) // If parent timer is not enabled then it is probably the start of a new day (after a night time server backup which kills timers)
{
parentTimer.Interval = 60000; // One minute
parentTimer.Elapsed += new ElapsedEventHandler(parentTimer_Elapsed); // Define what happens when elapsed
parentTimer.AutoReset = true; // Set timer to repeat
parentTimer.Enabled = true; // Start the timer
}
}
protected void btnCancel_Click(object sender, System.EventArgs e)
{
parentTimer.Stop();
...etc...
}
Note: I do not change ParentTimer at all in its elapsed method.
Basically ParentTimer governs a list of ChildTimers. If ParentTimer elapses it checks if one or more of the ChildTimers have elapsed too, if so, there is an event, if not then it resets the ChildTimer and carries on.
My suspicion is it's because the worker process for the page is stopping at the end of the request.
You could try increasing the request time out, but a better question is Can you explain why you're trying to do this ? What is the problem you're trying to solve ?
Remember, that regardless of all the fluff that ASP.Net puts around your code to make you feel comfortable (session state, viewstate etc), a web request is stateless and should be considered as a distinct pass of logic, it's not like a windows application where a background thread of code in your void Main(...) function is constantly running.
A timer is tied to the thread that created it and in the case of ASP.net the thread that handles each page request issued by a given user will change frequently due to the use of worker threads and the thread pool.
Using a timer at page-level simply won't work; you need to be tracking the state at Session-level (tied to the particular user) as your starting point.
In fact, I just wouldn't use timers at all in a web application, because their execution is simply not guaranteed.
If you're using this to run a background task - consider firing up your own worker thread in Application_Start or something like that. The thread will be terminated when the app pool recycles. You should also look at manually shutting the thread down the application is being shut down too.
Be careful with this, however, this thread can't assume it's always the only one running - due to IIS overlapped recycling, when a new one fires up the old one could still be running in the old AppDomain.

Add content asynchronously (threading + ajax)

Ok what id like to do is to load a page that displays 90% of content, and load the last 10% asynchronously.
As im rendering the page i programatically create an update panel which i pass to a thread. When this thread finishes it then updates the updatepanel on the main thread.
public void test(object parameter)
{
Thread.Sleep(2000);
var updpanel = (UpdatePanel)parameter;
updpanel.ContentTemplateContainer.Controls.Add(new LiteralControl("HI"));
updpanel.Update();
}
protected void Page_Load(object sender, EventArgs e)
{
var th = new Thread(new ParameterizedThreadStart(test));
var updpanel = new UpdatePanel() { UpdateMode = UpdatePanelUpdateMode.Conditional };
ContentPlaceHolder1.Controls.Add(updpanel);
th.Start(updpanel);
}
Failing this, in a single threaded approach, do i just keep polling the page to see if it has finished or not?
One thing to keep in mind is, even though ASP.Net development seems like it's closely related to windows development, there's a big difference: your code to handle a request, most of the time, is executed in a fraction of a second and done... In this example, once the main thread has completed, the generated page has already been sent to the requestor, leaving your secondary thread running in the background of your server, working on a page that has already been sent out.
What you'll probably need to do is generate the 90% of the page, and then send it out. On your page, you will need to use ajax to, on page load (for the client), request the other 10% from the server... You'll probably want to do the javascript with a library like jquery, and on the server end setup a web service to handle the requests.
You cannot use threading this way on the server. Your second thread will probably not complete until after the page have been processed and the request lifecycle is complete.
Depending on what you are trying to achieve: do you need to process data in parallel server-side you should look into Asynchronous Pages in ASP.Net 2.0.
Another approach would be to render the page ("90%" as you call it) and use ajax on the client to request additional data.

Categories

Resources