Multiple BeginGetResponse inside BackgroundWorker - c#

I have UI code that utilizes BackgoundWorker for processing of expensive operations.
Inside DoWork is the metod that sends multiple web requests to remote web-server via BeginGetResponse.
The UI part is:
private void start_Click(object sender, RoutedEventArgs e)
{
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
if (bw.IsBusy != true)
{
bw.DoWork += new DoWorkEventHandler(Processing.FormWebRequests);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Processing.FinishBw);
bw.RunWorkerAsync();
}
}
DoWork executes following:
public static void FormWebRequests(object sender, DoWorkEventArgs e)
{
foreach (webSites websiteitem in websites)
{
//Creation of webRequest object
webRequest.BeginGetResponse(new AsyncCallback(FinishWebRequest), webRequest);
}
}
And finally, callback method:
private static void FinishWebRequest(IAsyncResult result)
{
using (HttpWebResponse response = wr.EndGetResponse(result) as HttpWebResponse)
{
//Parsing httpResponse
}
}
Obviously, BackgroundWorker fires RunWorkerCompleted right after last BeginGetResponse sent. The problem is that I would like BackgroundWorker to fire RunWorkerCompleted after last EndGetResponse is finished.
Is this possible? Or should I use different async pattern?

BeginGetResponse is already async. This method returns immediately. When the response is completed, FinishWebRequest will be fired. So, you don't need to use BackgroundWorker.
This is Event driven.

Related

Trouble with UI Threads and Backgroundworker

What I'm trying to achieve is simple. I have a dynamic timer (one that can be changed by the user) which calls on background worker to go and fetch the user's external IP address. The combination of Timer and BackgroundWorker is causing some problems. Here's the code:
namespace IPdevices
{
/// <summary>
/// Interaction logic for Main.xaml
/// </summary>
public partial class Main : Window
{
private readonly BackgroundWorker worker;
private IPret iprep;
private Timer timer;
public Main(Client client)
{
InitializeComponent();
iprep = new IPret();
startClock();
worker = new BackgroundWorker();
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.WorkerReportsProgress = true;
worker.ProgressChanged += worker_ProgressChanged;
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ipAdd.Content = e.UserState;
}
private void startClock()
{
timer = new Timer();
timer.Interval = 2000;
timer.Elapsed += new ElapsedEventHandler(clockTimer_Tick);
timer.Start();
}
private void clockTimer_Tick(object sender, ElapsedEventArgs e)
{
timer.Stop();
worker.RunWorkerAsync();
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
Console.WriteLine("Checking ip");
iprep.refresh();
worker.ReportProgress(0, iprep.getExternalIp());
Console.WriteLine("Found ip");
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
timer.Start();
}
}
}
Essentially, once the timer fires, I wish to fetch the ip address and output on a label in the application. However, I get an exception in the ProgressChanged method saying that it can't be changed because another thread owns it. Which thread is that? Is it the iprep that is owned by another thread? In fact, RunWorkerCompleted never gets fired. I'm having trouble understanding which threads own what and how objects are locked...Any insight would be appreciated.
This appears to fix it in my test of it
private void clockTimer_Tick(object sender, ElapsedEventArgs e)
{
timer.Stop();
Action a = () =>
{
worker.RunWorkerAsync();
};
Application.Current.Dispatcher.BeginInvoke(a);
}
Also, I'll note this is consistent behavior for Timer in WPF (I hadn't used it in WPF before); trying ipAdd.Content = "Tick"; in the clockTimer_Tick causes the same error. System.Timers.Timer's tick event does not happen on the UI thread.
Replace all your code by the few lines shown below. The Tick handler is executed in the UI thread. Still it asynchronously runs a background operation and does not block the UI thread.
private void StartClock()
{
var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(2) };
timer.Tick += async (o, e) => await GetIP();
timer.Start();
}
private async Task GetIP()
{
Debug.WriteLine("Checking ip");
await Task.Run(() =>
{
// Get the IP asynchronously here
});
Debug.WriteLine("Found ip");
// Update the UI here
}
ipAdd is an UI element if I am not mistaken. If it is then the problem lies on cross threading.
What happened is that Background worker is going to be running on a different thread than the UI thread. If you want to modify UI element's property you need to do it on the UI thread. One option is to use Dispatcher.Invoke but since you are using WPF, there is a better way to do it.
Do a search about MVVM design patter and move the background code into View Model. Then you could do something like
string _XXContent
public string XXContent
{
get
{
return _XXContent;
}
set
{
_XXContent = value;
OnPropertyChanged("XXContent");
}
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
XXContent = e.UserState;
}
xaml :
<TextBox Content={Binding XXContent}/>
Edit:
If you are on c# 5 then you should look into async/IProgress as well an get rid of Background worker.

How to call web service without blocking execution of client?

I have a Windows Forms application which makes calls to web services via proxies generated with SvcUtil from WSDL descriptors. These calls can last for minutes, and during this time I don't want the client app to 'freeze out'. What do I have to do to achieve this? I guess something Threading related, but I'm not sure how to manage return values and parameters in that case.
You could use a BackgroundWorker.
private void wrk_DoWork(object sender, DoWorkEventArgs e)
{
// Do your work here
}
private void wrk_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Executed when worker completed its execution
}
private void StartIt()
{
BackgroundWorker wrk1 = new BackgroundWorker();
wrk1.DoWork += wrk_DoWork;
wrk1.RunWorkerCompleted += wrk_RunWorkerCompleted;
wrk1.RunWorkerAsync();
}
I'd go for a background worker.
Set the RunWorkerCompleted event and DoWork, run it and when you get your result in DoWork, set the event argument to your result (e.Result).
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.RunWorkerAsync();
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
// Do your processing
e.Result = result;
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
ResultLabel.Text = (string)e.Result;
}
The examples aren't tested, but your IDE should help you out. Also you will have to resolve the BackgroundWorker, or just add
using System.ComponentModel;
More information here: http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx
Hope it helps!
You can use methods that start with Begin......
e.g, use BeginAbc() instead of Abc()
I would recommend looking into BackgroundWorkers..
BackgroundWorker proxyWorker = new BackgroundWorker();
proxyWorker.DoWork +=
(sender, args) =>
{
//make proxy call here
};
proxyWorker.RunWorkerAsync();

Download file with backgroundWorker

i have created the downloader file
private void btnTestDownload_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
and work! but
private void btnTestDownload_Click(object sender, EventArgs e)
{
backgroundWorker1.CancelAsync();
}
the backgroundWorker dos not stop!
CancelAsync does not cause the worker to stop. You have to do that manually. Inside the worker method, you have to periodically check it's CancellationPending property to see if it should cancel or not.
So basically the body of the DoWork method should be something like this:
foreach( var something in somethingelse )
{
if (worker.CancellationPending == true) {
e.Cancel = true;
return;
}
//do your work here
}
If you inside your worker method just call some other method that itself takes a long time to complete, and you do not have the possibility to periodically check the CancellationPending variable yourself, then it's not easy to stop the worker on command without forcefully destroying the thread.
See MSDN:
When you call CancelAsync, your worker method has an opportunity to
stop its execution and exit. The worker code should periodically check
the CancellationPending property to see if it has been set to true.
It sounds like you've got completely the wrong idea about the purpose of a background worker. If you want to download a single file asyncronously with the ability to cancel it, all this functionality is built into the WebClient class.
Background worker is for long running tasks which are, on the whole, processor intensive. For example, if the file you were downloading were a large text file and you needed to parse each line of the text file, you could use the background worker for that, e.g.
Downloading a File
WebClient Client = new WebClient();
public void TestStart()
{
//Handle the event for download complete
Client.DownloadDataCompleted += Client_DownloadDataCompleted;
//Start downloading file
Client.DownloadDataAsync(new Uri("http://mywebsite.co.uk/myfile.txt"));
}
void Client_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
{
//Remove handler as no longer needed
Client.DownloadDataCompleted -= Client_DownloadDataCompleted;
//Get the data of the file
byte[] Data = e.Result;
}
public void TestCancel()
{
Client.CancelAsync();
Client.DownloadDataCompleted -= Client_DownloadDataCompleted;
}
Processing a File
BackgroundWorker worker = new BackgroundWorker() { WorkerSupportsCancellation = true };
//Take a stream reader (representation of a text file) and process it asyncronously
public void ProcessFile(StreamReader Reader)
{
worker.DoWork += worker_DoWork;
worker.RunWorkerAsync(Reader);
}
public void CancelProcessFile()
{
worker.CancelAsync();
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
//Get the reader passed as an argument
StreamReader Reader = e.Argument as StreamReader;
if (Reader != null)
{
//while not at the end of the file and cancellation not pending
while (Reader.Peek() != -1 && !((BackgroundWorker)sender).CancellationPending)
{
//Read the next line
var Line = Reader.ReadLine();
//TODO: Process Line
}
}
}

Load objects into cache from new thread

I'm trying to use the BackgroundWorker class to start a new thread which loads a large number of objects into the cache when the website is started.
My code so far:
private void PreLoadCachedSearches()
{
var worker = new BackgroundWorker() { WorkerReportsProgress = false, WorkerSupportsCancellation = true };
worker.DoWork += new DoWorkEventHandler(DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(WorkerCompleted);
worker.RunWorkerAsync();
}
private static void DoWork(object sender, DoWorkEventArgs e)
{
// Do the cache loading...
var x = HttpContext.Current.Cache; // BUT the Cache is now null!!!!
}
private static void WorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Logging?
}
I put the code in Global.asax.cs and call PreLoadCachedSearches during the Application_Start event: The new thread is started, but it fails whenever it tries to access the cache via HttpContext.Current.Cache which is null. I assume HttpContext doesn't exist/isn't available in the new thread I'm kicking off with the BackgroundWorker.
I've also tried moving the code to a separate page and start the thread manually rather than via the Application_Start event - same problem.
If I call my cache-loading code in the context of the web application (i.e. no threading) it works just fine.
How do I work around this? Pass in a reference to the cache of the main thread or access it somehow?
This question is a continuation of this previous question, Asynchronous task in ASP.NET.
You don't have an HttpContext because the thread isn't involved in servicing an Http Request.
Try HttpRuntime.Cache
You can do it by passing HttpContex.Current as parameter;
private void PreLoadCachedSearches()
{
var worker = new BackgroundWorker() { WorkerReportsProgress = false, WorkerSupportsCancellation = true };
worker.DoWork += new DoWorkEventHandler(DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(WorkerCompleted);
worker.RunWorkerAsync(HttpContext.Current);
}
private static void DoWork(object sender, DoWorkEventArgs e)
{
HttpContext.Current = (HttpContext)e.Argument;
var x = HttpContext.Current.Cache;
}
private static void WorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Logging?
}

How to prevent from moving forward until a background task is completed?

I have an external library which has a method which performs a long running task on a background thread. When it's done it fires off a Completed event on the thread that kicked off the method (typically the UI thread). It looks like this:
public class Foo
{
public delegate void CompletedEventHandler(object sender, EventArgs e);
public event CompletedEventHandler Completed;
public void LongRunningTask()
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
bw.RunWorkerAsync();
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(5000);
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (Completed != null)
Completed(this, EventArgs.Empty);
}
}
The code that calls this library looks like this:
private void button1_Click(object sender, EventArgs e)
{
Foo b = new Foo();
b.Completed += new Foo.CompletedEventHandler(b_Completed);
b.LongRunningTask();
Debug.WriteLine("It's all done");
}
void b_Completed(object sender, EventArgs e)
{
// do stuff
}
In the button1_Click method, after I call b.LongRunningTask(), the Completed event fires off 5 seconds later on the UI thread, I update the UI and everything is great, since I don't have to deal with marshaling stuff to the proper thread.
However, I now have a need for the process to be synchronous (without changing the external library). In other words, after I kick off .LongRunningTask method, the next meaningful statement in that method should fire after .LongRunningTask has completed.
I've tried doing it with the EventWaitHandle (e.g. doing WaitOne after the call to LongRunningTask and then Resetting it in the Completed event, but that just locks everything up).
Is there a method in the .NET framework that allows me to do this?
I've tried doing it with the EventWaitHandle (e.g. doing WaitOne after the call to LongRunningTask and then Resetting it in the Completed event, but that just locks everything up).
That is exactly what will happen if you make this synchronous, by definition. You can't make it synchronous without blocking the UI thread.
Instead of having "the next meaningful statement in that method" fire after the operation, you'll need to either make it blocking, or have the meaningful statement fire in the callback.

Categories