Run asynchronous code inside backgroundworker - c#

I found a few examples on the internet but I'm having a hard time trying to run my async call inside a background worker. I'm working in WP8. What's missing?
Edit: The purpose of this is to update the values I'm reading from time to time. Let's say 1s.
Here is my async code, it just gets and stores some data in providers []:
public void getAllProvidersMethod()
{
try
{
sc.getAllProvidersCompleted += new EventHandler<ServiceReference1.getAllProvidersCompletedEventArgs>(callback);
sc.getAllProvidersAsync();
}
catch (System.Exception e)
{
MessageBox.Show(e.ToString());
}
}
public void callback(object sender, ServiceReference1.getAllProvidersCompletedEventArgs e)
{
try
{
providers = new String[e.Result.Length];
for (int i = 0; i < e.Result.Length; i++)
{
providers[i] = e.Result[i].ToString();
}
}
catch (System.Exception d)
{
MessageBox.Show(d.ToString());
}
}
This is my background worker:
private void networkWorker()
{
var obj = App.Current as App;
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(
delegate(object o, DoWorkEventArgs args)
{
BackgroundWorker b = o as BackgroundWorker;
getAllProvidersMethod();
});
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
delegate(object o, RunWorkerCompletedEventArgs args)
{
MessageBox.Show(" ");
});
bw.RunWorkerAsync();
}

Ok I managed to get it working!
For anyone that wants to run some async code automatically from time to time, forget about backgroundworkers, what you are looking for is a Timer.
Thank you Servy for the Timer hint.
Let's say I want to call asyncCall for each 5 seconds.
It's very simple. First define how long is your wait time between calls (how long you want it to wait before calling the same code again).
System.Windows.Threading.DispatcherTimer dt = new System.Windows.Threading.DispatcherTimer();
dt.Interval = new TimeSpan(0, 0, 0, 0, 5000); // HERE - for example 5000 is 5 seconds
dt.Tick += new EventHandler(dt_Tick);
dt.Start();
And then all you need is to write the code you want to repeat inside this method:
void dt_Tick(object sender, EventArgs e)
{
asyncCall();
}
In this case for each 5 seconds it will call asyncCall.

Related

C# Background Worker Append TextBox

first off I'd like to say I'm brand new to C# so I am not too aware with how the background worker is supposed to be implemented. I have a GUI program that basically pings a domain a returns the response to a textbox. I am able to get it to work normally, however, it freezes the code because it is running on the same thread which is why I am trying to implement a background worker.
Here is the basic setup
private void button1_Click(object sender, EventArgs e)
{
url = textBox1.Text;
button1.Enabled = false;
button2.Enabled = true;
bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);
bgWorker.RunWorkerAsync();
}
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
do
{
if (bgWorker.CancellationPending)
break;
Invoke((MethodInvoker)delegate { monitor(); });
} while (true);
}
public void monitor()
{
textBox2.AppendText("Status of: " + url + "\n");
Status(url);
System.Threading.Thread.Sleep(30000);
}
private void Status(string url)
{
// This method does all the ping work and also appends the status to the Text box as it goes through , as OK or down
}
I have not worked with bgworkers before and as you can imagine it's confusing. I've looked at tons of other articles and I can't seem to get it. Sorry if the code looks crazy, I'm trying to learn.
Use Microsoft's Reactive Framework (NuGet "System.Reactive.Windows.Forms" and add using System.Reactive.Linq;) and then you can do this:
private void button1_Click(object sender, EventArgs e)
{
var url = textBox1.Text;
Observable
.Interval(TimeSpan.FromMinutes(0.5))
.SelectMany(_ => Observable.Start(() => Status(url)))
.ObserveOn(this)
.Subscribe(status => textBox2.AppendText("Status of: " + status + "\n"));
}
You then just need to change Status to have this signature: string Status(string url).
That's it. No background worker. No invoking. And Status is nicely run on a background thread.
You've got several mistakes. First,
Invoke((MethodInvoker)delegate
{
monitor();
});
will call monitor() on your UI thread. In almost all cases you should not call methods on other threads. You especially should not call methods that block or do anything that takes more than a few milliseconds on your UI thread, and that is what this does:
System.Threading.Thread.Sleep(30000);
Instead of calling a method on another thread; submit immutable data to the other thread and let the thread decide when to handle it. There is an event already built in to BackgroundWorker which does that. Before you call bgWorker.RunWorkerAsync() do this:
url = new Uri(something);
bgWorker.WorkerReportsProgress = true;
bgWorker.WorkerSupportsCancellation = true;
bgWorker.ProgressChanged += Bgw_ProgressChanged;
private void Bgw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
textBox2.AppendText("Status of: " + url + ": " + e.UserState.ToString()
+ Environment.NewLine);
}
Your bgWorker_DoWork should look more like this:
void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
while (!bgw.CancellationPending)
{
System.Threading.Thread.Sleep(new TimeSpan(0, 0, 30));
var status = ResultOfPing(e.Argument as Uri);
bgw.ReportProgress(0, status);
}
e.Cancel = true;
}
and you should call it like this:
bgWorker.RunWorkerAsync(url);
You've got a second problem. BackgroundWorker creates a thread, and your thread is going to spend most of its time blocked on a timer or waiting for network responses. That is a poor use of a thread. You would be better off using completion callbacks or async/await.
The background worker is running on a thread pool thread, but your call to Status and Sleep is running on the UI thread. You need to move that stuff back into bgWorker_DoWork.
Try this code:
public partial class Form1 : Form
{
bool cancel;
public Form1()
{
InitializeComponent();
}
public void StartPinging()
{
this.cancel = false;
startButton.Enabled = false;
stopButton.Enabled = true;
responseBox.Clear();
responseBox.AppendText("Starting to ping server.");
responseBox.AppendText(Environment.NewLine);
var bw = new BackgroundWorker
{
WorkerReportsProgress = false,
WorkerSupportsCancellation = true
};
bw.DoWork += (obj, ev) =>
{
while (!cancel)
{
// Ping Server Here
string response = Server.PingServer();
this.Invoke(new UiMethod(() =>
{
responseBox.AppendText(response);
responseBox.AppendText(Environment.NewLine);
}));
}
};
bw.RunWorkerCompleted += (obj, ev) =>
{
this.Invoke(new UiMethod(() =>
{
responseBox.AppendText("Stopped pinging the server.");
responseBox.AppendText(Environment.NewLine);
startButton.Enabled = true;
stopButton.Enabled = false;
}));
};
bw.RunWorkerAsync();
}
delegate void UiMethod();
private void startButton_Click(object sender, EventArgs e)
{
StartPinging();
}
private void stopButton_Click(object sender, EventArgs e)
{
responseBox.AppendText("Cancelation Pressed.");
responseBox.AppendText(Environment.NewLine);
cancel = true;
}
}
public class Server
{
static Random rng = new Random();
public static string PingServer()
{
int time = 1200 + rng.Next(2400);
Thread.Sleep(time);
return $"{time} ms";
}
}
Erwin, when dealing with C# - threads and UI elements usually you will come across cross-thread operations i.e. Background thread with UI threads. This interaction needs to be done in thread safe way with the help of Invoke to avoid invalid operations.
Please look into below resource: InvokeRequired section.
https://learn.microsoft.com/en-us/dotnet/framework/winforms/controls/how-to-make-thread-safe-calls-to-windows-forms-controls

Having trouble with background worker processes in WPF application

I found a few other articles regarding using background worker which I've linked just below. I used the code examples and attempted to do this to run 3 different SQL Query's. In the code posted below when I break inside of RunBackGroundWorkerProcesses1 it does stop there and is called but method for worker_DoWork1 is never called even though it is in the code. I'm assuming that I've misunderstood this, can someone add some clarity.
Link I used for reference:
WPF Multithreading
Code:
public CallInformationMainScreen()
{
InitializeComponent();
//This is where i call the background processes
RunBackGroundWorkerProcesses1();
RunBackGroundWorkerProcesses2();
RunBackGroundWorkerProcesses3();
}
#endregion
#region Methods used to generate data for the UI
public string DisplayTotalDailyCalls()
{
DailyCallsQuery db = new DailyCallsQuery();
return db.GetNumber(SkillNumber);
}
public string DisplayTotalLastSevenCalls()
{
PrevSevenCallQuery db = new PrevSevenCallQuery();
return db.GetNumber(SkillNumber);
}
public string DisplayDailyAbandonCalls()
{
DailyAbandonQuery db = new DailyAbandonQuery();
return db.GetNumber(SkillNumber);
}
#endregion
#region Background worker processes
private void RunBackGroundWorkerProcesses1()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork1);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
System.Timers.Timer t = new System.Timers.Timer(10000); // 10 second intervals
t.Elapsed += (sender, e) =>
{
// Don't try to start the work if it's still busy with the previous run...
if (!worker.IsBusy)
worker.RunWorkerAsync();
};
}
private void RunBackGroundWorkerProcesses2()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork2);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
System.Timers.Timer t = new System.Timers.Timer(10000); // 10 second intervals
t.Elapsed += (sender, e) =>
{
// Don't try to start the work if it's still busy with the previous run...
if (!worker.IsBusy)
worker.RunWorkerAsync();
};
}
private void RunBackGroundWorkerProcesses3()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork3);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
System.Timers.Timer t = new System.Timers.Timer(10000); // 10 second intervals
t.Elapsed += (sender, e) =>
{
// Don't try to start the work if it's still busy with the previous run...
if (!worker.IsBusy)
worker.RunWorkerAsync();
};
}
private void worker_DoWork1(object sender, DoWorkEventArgs e)
{
// Whatever comes back from the lengthy process, we can put into e.Result
TotalDailyCalls = DisplayTotalDailyCalls();
e.Result = TotalDailyCalls;
}
private void worker_DoWork2(object sender, DoWorkEventArgs e)
{
// Whatever comes back from the lengthy process, we can put into e.Result
TotalDailyLast7Days = DisplayTotalLastSevenCalls();
e.Result = TotalDailyCalls;
}
private void worker_DoWork3(object sender, DoWorkEventArgs e)
{
// Whatever comes back from the lengthy process, we can put into e.Result
TotalDailyAbandon = DisplayDailyAbandonCalls();
e.Result = TotalDailyAbandon;
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// First, handle the case where an exception was thrown.
if (e.Error != null)
{
// handle the System.Exception
MessageBox.Show(e.Error.Message);
}
else if (e.Cancelled)
{
// now handle the case where the operation was cancelled...
ErrorHolder = "The operation was cancelled";
}
else
{
// Finally, handle the case where the operation succeeded
ErrorHolder = e.Result.ToString();
}
}
#endregion
You don't start your timers. See Timer.Start Method ().
private void RunBackGroundWorkerProcesses1()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork1);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
System.Timers.Timer t = new System.Timers.Timer(10000); // 10 second intervals
t.Elapsed += (sender, e) =>
{
// Don't try to start the work if it's still busy with the previous run...
if (!worker.IsBusy)
worker.RunWorkerAsync();
};
t.Start(); // Start the timer
}
I'm posting this to demonstrate an easier way to do this. It's not meant to be a direct answer to the question.
If you NuGet "System.Reactive" and the associated WPF libraries you can do this:
IDisposable subscription =
new []
{
Observable.Interval(TimeSpan.FromSeconds(10.0)).Select(x => DisplayTotalDailyCalls()),
Observable.Interval(TimeSpan.FromSeconds(10.0)).Select(x => DisplayTotalLastSevenCalls()),
Observable.Interval(TimeSpan.FromSeconds(10.0)).Select(x => DisplayDailyAbandonCalls()),
}
.Merge()
.ObserveOnDispatcher()
.Subscribe(x => ErrorHolder = x, e => MessageBox.Show(e.Error.Message));
That's it. Job done. All of your code in techically one line of code.
BackgroundWorker.RunWorkerAsync() is only called when the Timer.Elapsed event is fired. Since the timer is set to 10 second intervals, the BackgroundWorker won't start for 10 seconds. You probably should call BackgroundWorker.RunWorkerAsync() after creating and initializing it so that it will start right away.

C# background thread worker

I am trying to read data from my USB buffer. However when I read data from the buffer I have to perform some operation on this data, and this takes time. In the mean time the external device observes that the buffer is full and stops writing data. I need to overcome this situation. THe processing involves reading the array and some UI operations , so I though I could put the entire operation of reading data into a background thread and read the data once the background thread has completed operation
BackgroundWorker bw = new BackgroundWorker();
// this allows our worker to report progress during work
bw.WorkerReportsProgress = true;
// what to do in the background thread
bw.DoWork += new DoWorkEventHandler(
delegate(object o, DoWorkEventArgs args)
{
BackgroundWorker b = o as BackgroundWorker;
// do some simple processing for 10 seconds
for (int i = 1; i <= 10; i++)
{
// report the progress in percent
b.ReportProgress(i * 10);
Thread.Sleep(1000);
}
//I have to keep reading from the buffer here
});
// what to do when progress changed (update the progress bar for example)
bw.ProgressChanged += new ProgressChangedEventHandler(
delegate(object o, ProgressChangedEventArgs args)
{
label1.Text = string.Format("{0}% Completed", args.ProgressPercentage);
});
// what to do when worker completes its task (notify the user)
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
delegate(object o, RunWorkerCompletedEventArgs args)
{
label1.Text = "Finished!";
//I have to use the data from the buffer here
});
bw.RunWorkerAsync();
But even with this approach I still am not reading the buffer continously since only after the operation on the UI completes can I call the background worker again. Is there any way to continously read the buffer(like into a large 2d array) and keep notifying me when each 1d array of the buffer is full? The main idea is the task in the worker should not be stopped, however I still need to get the data from the worker task(know that it has completed). What would be the best way to achieve this?
Maybe in your case using the following class would come handy :
public class BackgroundTimer : BackgroundWorker
{
private ManualResetEvent intervalManualReset;
private enum ProcessStatus { Created, Running, JobCompleted, ExceptionOccured };
private ProcessStatus processStatus = new ProcessStatus();
public int Interval { get; set; }
public BackgroundTimer()
{
this.processStatus = ProcessStatus.Created;
this.WorkerSupportsCancellation = true;
this.Interval = 1000;
}
protected override void OnRunWorkerCompleted(RunWorkerCompletedEventArgs e)
{
base.OnRunWorkerCompleted(e);
if (processStatus == ProcessStatus.ExceptionOccured)
// Log : Process stopped;
processStatus = ProcessStatus.JobCompleted;
}
protected override void OnDoWork(DoWorkEventArgs e)
{
while (!this.CancellationPending)
{
try
{
base.OnDoWork(e);
this.Sleep();
}
catch (Exception exception)
{
//Log excepption;
this.processStatus = ProcessStatus.ExceptionOccured;
this.Stop();
}
}
if (e != null)
e.Cancel = true;
}
public void Start()
{
this.processStatus = ProcessStatus.Running;
if (this.IsBusy)
return;
this.intervalManualReset = new ManualResetEvent(false);
this.RunWorkerAsync();
}
public void Stop()
{
this.CancelAsync();
this.WakeUp();
this.Dispose(true);
}
public void WakeUp()
{
if (this.intervalManualReset != null)
this.intervalManualReset.Set();
}
private void Sleep()
{
if (this.intervalManualReset != null)
{
this.intervalManualReset.Reset();
this.intervalManualReset.WaitOne(this.Interval);
}
}
public void Activate()
{
if (!this.IsBusy)
// Log : Process activated.
this.Start();
}
}
EDIT :
Usage :
private void InitializeThread()
{
var timer = new BackgroundTimer();
timer.Interval = 1000; // sleep 1 second between each iteration.
timer.DoWork += timer_DoWork;
timer.Start();
}
void timer_DoWork(object sender, DoWorkEventArgs e)
{
// your desired operation.
}
I hope it helps.

How to check every 30seconds with dispatchertimer without affect the UI in c#?

I hav tried the below code for checking reports from server in every 30seconds,but after 30seconds tick,The application hangs for several seconds.How to avoid the Hanging problem.
The below code am tried,what change want to given in this?
System.Windows.Threading.DispatcherTimer dispatcherTimer2 = new System.Windows.Threading.DispatcherTimer();
dispatcherTimer2.Tick += new EventHandler(dispatcherTimer2_Tick);
dispatcherTimer2.Interval = new TimeSpan(0, 0, 30);
Public void dispatcherTimer2_Tick(object sender, EventArgs e)
{
dispatcherTimer2.start();
//code for function call autoreport();
}
DispatcherTimer callback is executed on main UI thread and blocks it.
Use System.Threading.Timer and if you need to update user interface from timer callback use one of
Dispatcher.Invoke
overloads.
In code something like this
public partial class MainWindow : Window
{
System.Threading.Timer timer;
public MainWindow()
{
InitializeComponent();
timer = new System.Threading.Timer(OnCallBack, null, 0, 30 * 1000);
}
private void OnCallBack(object state)
{
//code to check report
Dispatcher.Invoke(() =>
{
//code to update ui
this.Label.Content = string.Format("Fired at {0}", DateTime.Now);
});
}
}
var timer = new System.Threading.Timer(
delegate
{
//--update functions here (large operations)
var value = Environment.TickCount;
//--run update using interface thread(UI Thread)
//--for WinForms
Invoke(
new Action(() =>
{
//--set the value to UI Element
}));
//--for WPF
Dispatcher.Invoke(
new Action(() =>
{
//--set the value to UI Element
}), null);
});
var period = TimeSpan.FromSeconds(30);
timer.Change(period, period);
I hope it helps.
This is worked for me
public Form1()
{
InitializeComponent();
var timer = new System.Timers.Timer(500);
// Hook up the Elapsed event for the timer.
timer.Elapsed += timer_Elapsed;
timer.Enabled = true;
}
void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Invoke(
new Action(() =>
{
label1.Text += "Test Label";
Application.DoEvents();
}));
}

Background worker stealing main thread

So I can't say for sure this is the issue but I'm just about positive it is. I have a recordset of IVR calls to make. I put the data for each one in a concurrent queue and start 5 background workers to start working from the queue. However, after making 2 calls, the calls stop coming until one person hangs up, then it moves on to call number 3,4,5 etc. Are the any issues with this code?
It seems like the background workers are blocking eachother from calling the same method...? Is that possible?
private ConcurrentQueue<DataTable> _ivrCallsQueue = new ConcurrentQueue<DataTable>();
private List<BackgroundWorker> _ivrCallers = new List<BackgroundWorker>();
public overrid void Process()
{
foreach(DataRow row in _tblRecordsToProcess.Rows)
{
_workingActionItem = actionItemDAL.GetActionItemFromId(Convert.ToInt32(row["FNActionItemId"].ToString()));
var workingActionItemsTable = actionItemDAL.GetActionItemParamValues(Convert.ToInt32(row["FNActionItemId"].ToString()));
ivrCallsQueue.Enqueue(workingActionItemsTable);
}
StartCalls();
while (_ivrCallers.Count != 0)
{
testurls = testurls;
}
}
private void StartCalls()
{
int maxLines = 5;
if (_ivrCallsQueue.Count < maxLines)
{
maxLines = _ivrCallsQueue.Count;
}
for (int i = 0; i < maxLines; i++)
{
DataTable workingCall = new DataTable();
_ivrCallsQueue.TryDequeue(out workingCall);
BackgroundWorker ivrCaller = new BackgroundWorker();
_ivrCallers.Add(ivrCaller);
ivrCaller.DoWork += delegate(object sender, DoWorkEventArgs e)
{
RequestIVR(workingCall, Convert.ToInt32(workingCall.Rows[2][0].ToString()));
_ivrCallers.Remove(ivrCaller);
};
ivrCaller.RunWorkerCompleted += (bw_AnalyzeResults);
ivrCaller.RunWorkerAsync();
}
}
private void bw_AnalyzeResults(object sender, RunWorkerCompletedEventArgs e)
{
DataTable workingCall = new DataTable();
if (_ivrCallsQueue.Count != 0)
{
_ivrCallsQueue.TryDequeue(out workingCall);
BackgroundWorker ivrCaller = new BackgroundWorker();
ivrCaller.DoWork += delegate(object completeSender, DoWorkEventArgs completeArgs)
{
RequestIVR(workingCall, Convert.ToInt32(workingCall.Rows[2][0].ToString()));
_ivrCallers.Remove(ivrCaller);
};
ivrCaller.RunWorkerCompleted += (bw_AnalyzeResults);
ivrCaller.RunWorkerAsync();
}
else
{
}
}
private void RequestIVR(DataTable workingTable,int fnActionItemID)
{
var urlRequest = "http://uccx_http_trigger:9080/test?strTestMode=1&strTaskID=" + fnActionItemID;
var webClient = new WebClient { UseDefaultCredentials = true, Proxy = WebRequest.DefaultWebProxy };
DecodeResponseType(GetValueFromElement("Response Code was ", webClient.DownloadString(urlRequest)));
}
This will spawn at most five threads that each attempt to pull the next item from the queue and process it. If the queue is empty the attempt will fail and the thread will simply exit:
private List<System.Threading.Thread> Threads = new List<System.Threading.Thread>();
private ConcurrentQueue<DataTable> _ivrCallsQueue = new ConcurrentQueue<DataTable>();
private void StartCalls()
{
int maxLines = Math.Min(5 , _ivrCallsQueue.Count);
for (int i = 0; i < maxLines; i++ )
{
System.Threading.Thread T = new System.Threading.Thread(delegate()
{
DataTable workingCall;
while (_ivrCallsQueue.TryDequeue(out workingCall))
{
RequestIVR(workingCall, Convert.ToInt32(workingCall.Rows[2][0].ToString()));
}
});
Threads.Add(T);
T.Start();
}
}
The threads will keep running until all the items have been processed.
It looks like bw_AnalyzeResults does pretty much the same thing that StartCalls() does. In other words, when the background worker has finished its work, you immediately enqueue the same work to happen again, recursively forever?
By the looks of it, you want bw_AnalyzeResults to analyze the results returned by calling your web service. That is not what is happening at the moment.
The code below taken from the bw_AnalyzeResults event handler is scheduling a background job and making itself handle the RunWorkerCompleted event. So, presumably the software keeps going around and around executing bw_AnalyzeResults forever until you kill the process?
private void bw_AnalyzeResults(object sender, RunWorkerCompletedEventArgs e)
{
ivrCaller.DoWork += delegate(object completeSender, DoWorkEventArgs completeArgs)
{
RequestIVR(workingCall, Convert.ToInt32(workingCall.Rows[2][0].ToString()));
_ivrCallers.Remove(ivrCaller);
};
ivrCaller.RunWorkerCompleted += (bw_AnalyzeResults);
}

Categories

Resources