Running Something In a thread with feedback - c#

I have written a function which takes a whole bunch of files, zips them up and then allows the user to download this zip all through an asp.net website.
However, these zip files are going to be pretty large (like 1GB large), so it won't happen immediately, what i'd like to do is to be able to have this running on a seperate thread (possible?) while the user continues to navigate around the website, and once the zip is created, have some way of notifying them so they can then download this zip.
I was hoping for some pointers on how best to do this in c# and also in terms of UI.
Thanks in advance.

Use
Asynchronous Pages in ASP.NET 2.0
you can't wait too long in asp.net to complete the task due to the fear of page recycling , session expires , it would be great that you zip these files using some other process and update a flag either in database or somewhere in the private network that your zip component is ready !! your asp.net application should read this flag and than let the user know that their zip is ready to be downloaded.

You can use BackgroundWorker component. It has ability to raise progress event which you can use to give feedback to the main thread (like UI).
public void static Main()
{
var bw = new BackgroundWorkder();
bw.DoWork += _worker_DoWork;
bw.RunWorkerCompleted += _worker_RunWorkerCompleted;
bw.ProgressChanged += _worker_ProgressChanged;
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = false;
//START PROCESSING
bw.RunWorkerAsync(/*PASS FILE DATA*/);
}
private void _worker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bw = sender as BackgroundWorker;
var data = e.Argument as /*DATA OBJECT YOU PASSED*/;
//PSEUDO CODE
foreach(var file in FILES)
{
zipFile;
//HERE YOU CAN REPORT PROGRESS
bw.ReportProgress(/*int percentProgress, object userState*/)
}
}
private void _worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Just update progress bar with % complete or something
}
private void _worker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
//...
}
else
{
//......
}
}

use the backgroundworker: http://msdn.microsoft.com/en-us/library/cc221403(VS.95).aspx

The BackgroundWorker object is probably what you are looking for.
Here is a good tutorial: http://dotnetperls.com/backgroundworker

Related

Background worker in windows form application

I have the following constellation:
MainForm.cs -> Including all my Form Elements
Program.cs -> includes the main part, which is a xmlreader/writer to alter xml attributes in xml files that can be as large as 4gb
So this little app works but of course the UI gets unresponsive and freezes which I want to avoid, I also hope to reduce the duration of this process on the way
I start the call of my xmlread/write method from a BtnClick event:
void BtnApplyChangesClick(object sender, EventArgs e)
{
Program p = Program.Instance;
pbApplyChanges.Minimum = 0;
pbApplyChanges.Step = 1;
Cursor.Current = Cursors.WaitCursor;
foreach(DataGridViewRow cr in dataGridView2.Rows)
{
pbApplyChanges.Maximum = dataGridView2.Rows.Count;
p.changeElements(cr.Cells["Filename"].Value.ToString(), txtTenant.Text, txtDate.Text, txtEvtId2.Text);
pbApplyChanges.PerformStep();
}
Cursor.Current = Cursors.Arrow;
MessageBox.Show("Job done");
}
In the call I use my singleton instance of Program.cs and my main Method there (changeElements) uses 4 String params, that are all taken from information in the Form! (I suppose this is kinda bad practice but it worked so far...)
When I tried to replace this method call with a backgroundWorker (itself made the method call then) I failed as the method call wasn't even made... I found out that UI elements can't be accessed from the BW thread, so I suppose this is also the reason for my method call not working?!
So how can I get this constellation to work? Do I have to pass all 4 string Params AND the class instance (of Program.cs) to the background worker? Is BW even the best tool for the job?
In general the BackgroundWorker shouldn't access any UI-Elements. It's an old advice in Winforms that accessing UI-Elements should just happen from the UI-Thread.
You can use the Background-Worker like this:
private void Main(string[] args)
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += Bw_DoWork;
bw.RunWorkerCompleted += Bw_RunWorkerCompleted;
//Parameter you need to work in Background-Thread for example your strings
string[] param = new[] {"Text1", "Text2", "Text3", "Text4"};
//Start work
bw.RunWorkerAsync(param);
}
//Do your Background-Work
private void Bw_DoWork(object sender, DoWorkEventArgs e)
{
string[] param = e.Argument as string[];
//Process your long running task
e.Result = null; //Set your Result of the long running task
}
//Taking your results
private void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//Apply your Results to your GUI-Elements
myTextBox1.Text = e.Result.ToString();
}
Background-Worker is some old school stuff by the way, so if you like to learn something new take a look here and inform yourself about the TPL. This gives you a better handling of asynchronous.
In fact I think it's not really good to store 4gb data in a XML-File. Do you think about a Database? Or split the XML-File in many XML-Files? So you would be able to read data in chunks.
I hope this helps you.
I don't use background worker for this. I use normal threads instead. Try this code:
public void ButtonDoWork_Click(eventArgs......) {
DoWorkThread = new Thread(new ThreadStart(DoWork)); // Setup thread
DoWorkThread.isBackground = true; // Its background so, we need to set background flag
DoWorkThread.Start(); // Start the thread
}
private Thread DoWorkThread: // our Thread object
private void DoWork() { // This void contains action that will be performed by thread
//TODO: Background processing. To update UI from another thread use Control.Invoke(...)
}
Please note, I don't tested this code - I write it from my memory and it's late so it can not work.
You can also read about Threads at MSDN :)

How to handle this asynchronous programming scenario in C#

I just had an interview 5 minutes back. I was given this scenario and he asked me the question on how to handle this in C# 1.0 or 2.0. He said there is a basic feature to handle this, I wasn't sure. Can somebody please help :(
Question:
There are 2 text boxes in Winform application and a button. One text box takes input value and when button is clicked, it process input in server which takes hell lot of time and finally displays the result in another textbox. As it takes very long time in server, the UI shouldn't be interupted, how do you handle this scenario he asked me :(
Answer I gave:
I told multithreading and said about async and await. He was expecting a simple way of handling this in C# 2.0 thing. I was guessing about asynchronous delegates. He wasn't convinced. Please someone explain me with little understandble code :)
You would run the long running process in a separate thread to the UI to prevent it hanging, perhaps a BackgroundWorker would be used for example: -
bgWorker.RunWorkerAsync([DATA TO PROCESS])//Passing in data to operate on
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
MyObject obj = (MyObject)sender;
//
// Do some work with the data on the server
//
// Report on progess, is it done?
bgWorker.ReportProgress();
}
You could also have a work complete method
private void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//Work is complete, notify user
}
You could also use a ThreadPool, which requires a little more set up but i find is more flexible. For example: -
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), [DATA TO PROCESS]);
Interlocked.Increment(ref workItems);
workItems would be a count of the number of items left to process, this could be used to keep track of whether the task is complete or not. We then define a DoWork method where we process the data and decrement our workItems counter. Once an item has been processed, we report progress via delegates such as: -
private delegate void ThreadDone(MyObject obj);
private delegate void TaskDone();
public void DoWork(object sender)
{
MyObject obj = (MyObject)sender;
this.Invoke(new ThreadDone(ReportProgress), result);
Interlocked.Decrement(ref workItems);
if (workItems == 0)
{
this.Invoke(new TaskDone(WorkComplete));
}
}
Report progress might look like this: -
private void ReportProgress(MyObject obj)
{
if (workItems >= 0)
{
//Job isn't complete, report progress
}
}
private void WorkComplete()
{
}
In .Net 2 winform applications, the simplest solution is to use a BackgroundWorker. Its events are raised on the UI thread so you don't need to do any marshalling yourself.
The usual pattern looks like:
BackgroundWorker bg = new BackgroundWorker();
bg.DoWork += delegate(object sender, DoWorkEventArgs e) {
try {
e.Result = server.LongRunningOperation();
}
catch(Exception ex) {
e.Error = ex;
}
};
bg.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e) {
//update UI
};
bg.RunWorkerAsync();

C# - Delete Folder

I want delete java folder with C#,
but I have little problem.
this is the code
private void setDebug(string value)
{
debug.Text = value;
}
private void buildButton_Click(object sender, EventArgs e)
{
// delete java folder
string java_folder = #"C:\Program Files\Java";
if (Directory.Exists(java_folder))
{
setDebug("Deleting Java folder...");
Directory.Delete(java_folder, true);
progressBar.Value += 10;
}
}
when I click on the button the program stuck, but when i delete the line Directory.Delete
it change the debug label to "Deleting java folder..."
I know that the program stuck because it delete the folder but i want it change the debug first before it delete the folder.
what to do? thanks for help :)
The reason that your code doesn't appear to be working is because of the way WinForms handles UI updates.
The UI will not repaint until your method buildButton_Click completes - and nor will the UI be responsive until that time. The Directory.Delete line is something that will take a long time to run, and so your program "sticks" and you don't see the debug label.
What you need to do is look into using threading - read up on Threads, Tasks or the BackgroundWorker class in order to understand how they work. Then, instead of calling Directory.Delete directly in your method, use one of those techniques to run the delete on a background thread.
You need to wrap your code in a different thread, like this:
private void setDebug(string value)
{
debug.Text = value;
}
private void buildButton_Click(object sender, EventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
string java_folder = #"C:\Program Files\Java";
if (Directory.Exists(java_folder))
{
setDebug("Deleting Java folder...");
worker.DoWork += (s, args) => // this is the off-thread code
{
// delete java folder
Directory.Delete(java_folder, true);
};
worker.RunWorkerCompleted += (s,args)=> // this goes off when .DoWork is done
{
progressBar.Value += 10;
};
// this invokes .DoWork handler (which we defined above)
worker.RunWorkerAsync();
}
}

Show a Animation during a loading

Well, what I am trying to do is show a animated gif while it reads a directory full of files, however the UI freezes, which is ok, but i would like to keep the gif running till the operation is finished. Any ideas?
I am doing it on a Windows Form using VS2010 C#
Here is some example code how you can Load your files aysnchronous. Maybe it helps you. I like this way more than using DoEvents. With DoEvents I had already have some ungood side-effects, therefore I try not to use it.
BackgroundWorker bgWorker = new BackgroundWorker() { WorkerReportsProgress=true};
bgWorker.DoWork += (s, e) => {
// Load here your file/s
// Use bgWorker.ReportProgress(); to report the current progress
};
bgWorker.ProgressChanged+=(s,e)=>{
// Here you will be informed about progress and here it is save to change/show progress. You can access from here savely a ProgressBars or another control.
};
bgWorker.RunWorkerCompleted += (s, e) => {
// Here you will be informed if the job is done.
// Use this event to unlock your gui
};
bgWorker.RunWorkerAsync();
You have two options.
Start a separate thread to handle the file operations.
periodically call Application.DoEvents() within the file loop. That will cause your app to process pending messages (thus updating your UI), but will negatively impact the speed of the file processing loop.
Posting from my phone so no example links.
Run enumeration is a separate thread and update the GUI in the main thread.
Would something like this work with backgroundWorker?
private void buttonRename_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
foreach (ListViewItem myitem in listView.Items)
{
try
{
//Rename
}
catch
{
}
}
}

Try codesnippet until condition is True

this is probably a nobraner, but I can't figure it out.
I've got this function which converts wav files to mp3. I call this from my button_click handle. The thing is, when the conversion is started, the rest of the code in the button_click handler continue, while the conversion is happening in a different thread.
Now, I need the rest of the code in the button_click handle so continue to try until a boolean is true, so that I know that the conversion is done before the rest of the code continues.
I've tried using Do While but it didn't seem to do the trick. Perhaps it's just me though..
Is this a client application? Sounds like a great application for BackgroundWorker.
To execute a time-consuming operation
in the background, create a
BackgroundWorker and listen for events
that report the progress of your
operation and signal when your
operation is finished.
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler
(bw_RunWorkerCompleted);
....
private void button1_Click(object sender, EventArgs e)
{
bw.RunWorkerAsync(filename);
}
static void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = (BackgroundWorker)sender;
string filename = (string)e.Argument;
e.Result = DoConversion(filename);
}
static void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
label.Text = "Done: " + e.Result.ToString();
DoSomethingWhenConversionComplete();
}
This is called a spin-wait and is not the best way to accomplish your task:
// IsConversionComplete will be set by some other thread
while(!IsConversionComplete){
Thread.Sleep(100);
}
// carry on
A much more efficient solution requires a synchronization structure like a mutex or use of events.

Categories

Resources