C# How to check internet connection in realiable and not block UI? - c#

while ago I was looking for some realiable way of checking internet connection, at same time i would like it not to render my aplication irresponsive, I found various examples like this code:
public static bool CheckForInternetConnection()
{
try
{
using (var client = new WebClient())
using (var stream = client.OpenRead("http://www.google.com"))
{
return true;
}
}
catch
{
return false;
}
}
That use WebClient, but main flaw of these solutions is fact they freeze entire application, and since I do connection tests every few minutes this behaviour is highly unwanted.
What i want to achieve is to get that piece of code working in a way it will execute but it will keep application waiting for response and at the same time it wont make UI irresponsive.
Cheers
MTH
EDIT:
I want to be for this code to be avaliable form multiple code paths, preferably as static method of some static class. Doing it as background worker does limit it in a way. I will try with separate thread, and see if it will bring effect that i want to achieve.
I just want to get all what happens during call of that simple method above(delay, all other operations waiting for method to fisnish), just without blocking UI, so while connection is checked app is waiting but doesn't hang

If you can't use a BackgroundWorker and you're targeting .NET 4.5 you can wrap that method inside a Task.
public static Task<bool> CheckInternetConnectionAsync( )
{
return Task<bool>.Run( ( ) => {
try
{
using ( var client = new WebClient( ) )
using ( var stream = client.OpenRead( "http://www.google.com" ) )
{
return true;
}
}
catch
{
return false;
}
} );
}
And whenever you need to check for internet connection do it like this ...
static async void CheckInternetConnection( )
{
//just an example how to read a value from Task
bool hasConnection = await CheckInternetConnectionAsync( );
}

You need to use multithreading to run the check on another thread so it does not interfere with your main application.
Thread thread = new Thread(() => ConnectionCheck());
thread.Start();
...
public static void ConnectionCheck()
{
bool result = CheckForInternetConnection();
//Do something with result
}
In your case it might be easier to use a BackgroundWorker to use your return value easier. You can run a task, store the output in the Result variable and use it when completed.
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.RunWorkerAsync("Name");
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
bool result = (bool)e.Result;
//Do something with Result
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = CheckForInternetConnection();
}

Related

c# which is the best way for doing a larger task without interrupting whole program

My question is i want to execute some operations like fetching the data ( format is string )from some URL . and i want run this process to be background. i have to call this operations whenever user needs this. like if a user clicks a button specified for this operation, it should execute the function and provide result to that user. Problem is when ever executing this no other program should not get interrupted. I want to run this Asynchronous way . i want to return the result which is downloaded from the URL
Here is my solution using thread
namespace xyz
{
public class newWinForm : Form
{
SomeClass someClass = new SomeClass();
public newWinForm()
{
Thread backgroundThread = new Thread(DoWork);
backgroundThread.IsBackground = true;
backgroundThread.Start();
}
void DoWork()
{
try
{
Console.WriteLine("Doing some work...");
using(WebClient cl = new WebClient())
{
string result = cl.DownloadString("http://www.......com");
}
Thread.Sleep(1000);
}
finally
{
Console.WriteLine("This should be always executed");
}
}
private void getDataFrmUrlButton_Click(object sender, EventArgs e)
{
Thread backgroundThread = new Thread(DoWork);
backgroundThread.IsBackground = true;
backgroundThread.Start();
}
}
You can use backgroundworker class in order to achieve your task
private BackgroundWorker bg1 = new BackgroundWorker();
bg1.DoWork += bg1_DoWork;
private void bg1_DoWork(object sender, DoWorkEventArgs e)
{
//the function you want to execute
}
In this case your operation is I/O bound, so an asynchronous approach is best. To do this you can use the async keyword on your events.
private async void getDataFrmUrlButton_Click(object sender, EventArgs args)
{
using(var client = new WebClient())
{
string result = await client.DownloadStringTaskAsync(uri);
// Do stuff with data
}
}
This post gives some good resources for more information on async/await.
If you want a more enterprise based solution you can have a look at Hangfire (https://www.hangfire.io/).
While normally targeted at ASP.NET solutions you can also run it as part of a windows service and use that in conjunction with your WinForm based application(s). It will allow you to easily hand off long running tasks and track them even if you don't want to to use TPL to do it yourself.

Main process gets frozen after starting another thread

I am trying to write an application which transfers data between 2 systems. This application is used by a user, so it is WinForm application. When data transfering is started by a click of the user, the GUI gets frozen even though I start the data transfering in another thread. I am doing something wrong but I couldnt figure it out. here is my SIMPLIFIED code below....
What am I doing wrong?
// Button Click Event
private void btnStart_Click(object sender, EventArgs e)
{
StartThread();
}
// This starts the threaad.
public static void StartThread()
{
string msg = string.Empty;
int i = 0;
continue_ = true;
if (list != null)
{
while (continue_)
{
i++;
Thread.Sleep(5000);
Thread thrd1 = new System.Threading.Thread(() => Test());
thrd1.Start();
}
}
}
// This is a simplified code.
public static void Test()
{
string msg = string.Empty;
int i = 0;
continue_ = true;
while (continue_)
{
i++;
Thread.Sleep(5000);
FormMain.dal.ExecuteQuery("INSERT INTO A_TEST VALUES('"+i+"')",null,CommandType.Text,out msg);
}
}
Your StartThread() method includes a Thread.Sleep(5000) ... this is happening in your button click method, thus is making the UI thread sleep. Also, it looks like you have an infinite loop on the UI thread as continue_ never gets set to false
I'm guessing what you're trying to achieve here, but this may help:
public static void StartThread()
{
Thread thrd1 = new System.Threading.Thread(() => Test());
thrd1.Start();
}
Let's have a look at this block in StartThread:
while (continue_)
{
i++;
Thread.Sleep(5000);
Thread thrd1 = new System.Threading.Thread(() => Test());
thrd1.Start();
}
You have a while loop dependen on continue_, but you never change it to false. So you get first of all an infinite loop, which causes the GUI to freeze.
why you are modifying i, but never using it, so just remove it.
You don't need also Thread.Sleep(5000);. However, if you really want to wait a time period, you can use an async delay. It will give the GUI free, so that the GUI works until the delay is finished. But for this, you have to declare StartThread as async.
In your:
if (list != null)
{
while (continue_)
{
i++;
Thread.Sleep(5000);
Thread thrd1 = new System.Threading.Thread(() => Test());
thrd1.Start();
}
}
You use Thread.Sleep(5000);
This however still targets your main thread.
I would suggest you to remove this line.
Also, why do you use the variable 'i' while you never use it?

Pause task execution

I have a long running task that behaves like a transaction - it involves many operations where success of one depends on success of another.
class MyTransaction
{
public void Execute()
{
StopServices();
BackupFiles();
OverwriteFiles();
BackupDatabases();
RunChangeScripts();
... and few others
}
public void RollBack() { }
}
class MyTransactionManager
{
public RunTransactions()
{
Task.Factory.StartNew(() => {
new MyTransaction().Execute();
});
}
}
This is just a pseudo-code of the real application where different operations are provided by different components of the system. There is an underlying GUI (WinForms) that displays progress using a progress bar and few other thing that have to stay responsive no matter what happens. Transactions are all really long running so there is no need to specify it when starting tasks (using TaskCreationOptions), it always runs in a new thread. Progress from transactions is reported back to the GUI using events.
Now, there is a request that if something during execution of a transaction fails it won't immediately roll back as it currently does. They want to pop up a message box in the GUI giving a user an option to decide whether to roll back or fix the error and continue from the last successful point.
So I need somehow implement a blocking. I thought that I could just raise another event, pop up a message box and say "Hey, fix it and then press ok". And bind that OK click event to my outer manager (public API) which can delegate requests directly to my transactions. And blocking would just actively run a while loop checking some bool property.
Now I am thinking that passive blocking would be better but I don't really know how to do it. Could you please advise me?
EDIT: And I don't really want to use Thread.Sleep, because these errors can take various time to fix. Depends on an error and a person who is fixing it.
And blocking would just actively run a while loop checking some bool property.
That's not blocking, it's called busy waiting and it's something you should avoid.
If you want to have synchronization like this between two threads, one way is to use ManualResetEvent:
AskUser(); // doesn't block
shouldRollbackEvent.WaitOne();
if (shouldRollback) …
And on your UI thread:
shouldRollback = …;
shouldRollbackEvent.Set();
(This assumes both parts of the code execute within the same object.)
May be you can try something like this
private static Task<bool> WaitTillUserInput()
{
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
uiSynchronizationContext.Post(x =>
{
if (MessageBox.Show("Do you want to rollback...?", "Please confirm", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
tcs.SetResult(true);
}
else
{
tcs.SetResult(false);
}
}, null);
return tcs.Task;
}
C# 5.0
public async void Execute()
{
...Do something
//Encountered an error
var doRollBack = await WaitTillUserInput();
if(doRollBack)
{
//rollback here
}
}
C# 4.0
public void Execute()
{
...Do something
//Encountered an error
var doRollBackTask = WaitTillUserInput();
doRollBackTask.ContinueWith(antecedent =>
{
if (antecedent.Result)
{
//rollback here
}
});
}
EventWaitHandle _wait;
private async void buttonStart_Click(object sender, EventArgs e) {
_wait = new EventWaitHandle(true, EventResetMode.ManualReset);
await Task.Run(() => GoInc());
}
private void buttonPause_Click(object sender, EventArgs e) {
_wait.Reset();
}
private void buttonResume_Click(object sender, EventArgs e) {
_wait.Set();
}
EventWaitHandle _wait;
private void GoInc() {
for (int i = 0; i < 10000; i++) {
_wait.WaitOne();
Thread.Sleep(100);
}
}

WPF/C# Don't block the UI

I've an existing WPF application, which has several sections. Every section is a UserControl, that implements an interface.
The interface specify two methods: void LoadData([...]) and bool UnloadData().
Those method are called by the UI thread, so we need to do our work in backgroundworker if it's time consuming.
No problems with LoadData since we can update the UI asynchronously. The problem is with UnloadData().
This should return if we can really leave the current view.
This is computed with the current status of data(Saved/modified/Invalid):
Saved return true,
Invalid asks if you want to stay to save some
correct data or leave without saving
Modified tell you that you can
either cancel your change(return true), either continue to
edit(return false), either save you current data(return true)
The problem is with the "Modified -> Save". This is a time consuming method, so to respect the philosophy of the application, we should run this in a background thread(with a busy indicator).
But if we just launch the thread and go to the next section, it will return "true" to the method call, and we will directly launch the next view.
In my case, loading the next view before our local data is saved can be a problem.
So:
Is there a way to wait on the background thread to finish before returning "true", WITHOUT blocking the UI?
public bool UnloadData(){
if(...){
LaunchMyTimeConsumingMethodWithBackgroundWorker();
return true;//Only when my time consuming method ends
}
//[...]
}
Important EDIT
Maybe I wasn't clear enought: I know how to use a BackgroundWorker, or TPL. My problem is that the parent class(the one which call the UnloadData()" is a class that I cannot edit(for multiple reasons: It's in another DLL that will not be reloaded, it already works with 70+ userControls, all in separate projects(dll), loaded by reflection.
This wasn't my choice, I don't find it good, but I've to deal with it now. I'm mostly looking for way to make my method wait on the return of my method. I'm not sure if it is possible. But I'm looking for a workaround, it will spare me weeks of works.
Ok now I'm excited, because I think I may have discovered something on my own...
So, what you do is this: You create a DispatcherFrame, push that frame onto the Dispatcher, and in the RunWorkerCompleted you set the Continue of the Frame to false.
This is the code so far:
public void Function()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += TimeConsumingFunction;
var frame = new DispatcherFrame();
worker.RunWorkerCompleted += (sender, args) =>
{
frame.Continue = false;
};
worker.RunWorkerAsync();
Dispatcher.PushFrame(frame);
}
private void TimeConsumingFunction(object sender, DoWorkEventArgs doWorkEventArgs)
{
Console.WriteLine("Entering");
for (int i = 0; i < 3; i++)
{
Thread.Sleep(1000);
}
Console.WriteLine("Exiting");
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
Function();
Console.WriteLine("Returns");
}
You should implement a dependency property "IsBusy" of type bool, that you set to TRUE before starting the BackgoundWorker, and then to FALSE when the work is complete.
On the UI, you bind to that property whatever functionality you want disabled during the processing(like the button for loading the next view, etc.); or maybe showing a "Cancel" button.
You should not "wait" for the operation to complete, you can retrieve the result in an additional variable, that the BackgroundWorker will set:
BackgroundWorker _bw;
bool _returnValue = false;
private void button_Click(object sender, RoutedEventArgs e)
{ // if starting the processing by clicking a button
_bw = new BackgroundWorker();
IsBusy = true;
_bw.DoWork += new DoWorkEventHandler(_bw_DoWork);
_bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_bw_RunWorkerCompleted);
_bw.RunWorkerAsync();
}
void _bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
IsBusy = false;
// retrieve the result of the operation in the _returnValue variable
}
void _bw_DoWork(object sender, DoWorkEventArgs e)
{
_returnValue = UnloadData();
}
private bool UnloadData()
{
if (...)
{
LaunchTimeConsumingMethod();
return true;
}
else
return false;
//etc ...
}
public bool IsBusy
{
get { return (bool)GetValue(IsBusyProperty); }
set { SetValue(IsBusyProperty, value); }
}
// Using a DependencyProperty as the backing store for IsBusy. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsBusyProperty =
DependencyProperty.Register( ... )
You may be able to try using the new "await" features of .NET 4.5.
The await keyword allows you to await the completion of a Task object, without blocking the UI.
Try this modification:
public async bool UnloadData()
{
if(...)
{
await Task.Factory.StartNew(() =>
{
LaunchMyTimeConsumingMethod();
});
return true;//Only when my time consuming method ends
}
//[...]
}
Treat UnloadData as a async operation and let the async/await features handle both the case when it completes synchronously and when it needs to complete asynchronously:
public async Task<bool> UnloadData(){
if(...){
// The await keyword will segment your method execution and post the continuation in the UI thread
// The Task.Factory.StartNew will run the time consuming method in the ThreadPool
await Task.Factory.StartNew(()=>LaunchMyTimeConsumingMethodWithBackgroundWorker());
// The return statement is the continuation and will run in the UI thread after the consuming method is executed
return true;
}
// If it came down this path, the execution is synchronous and is completely run in the UI thread
return false;
}
private async void button_Click(object sender, RoutedEventArgs e)
{
// Put here your logic to prevent user interaction during the operation's execution.
// Ex: this.mainPanel.IsEnabled = false;
// Or: this.modalPanel.Visibility = Visible;
// etc
try
{
bool result = await this.UnloadData();
// Do whatever with the result
}
finally
{
// Reenable the user interaction
// Ex: this.mainPanel.IsEnabled = true;
}
}
EDIT
If you can't modify the UnloadData, then just execute it on the ThreadPool, as #BTownTKD noted:
private async void button_Click(object sender, RoutedEventArgs e)
{
// Put here your logic to prevent user interaction during the operation's execution.
// Ex: this.mainPanel.IsEnabled = false;
// Or: this.modalPanel.Visibility = Visible;
// etc
try
{
// The await keyword will segment your method execution and post the continuation in the UI thread
// The Task.Factory.StartNew will run the time consuming method in the ThreadPool, whether it takes the long or the short path
bool result = await The Task.Factory.StartNew(()=>this.UnloadData());
// Do whatever with the result
}
finally
{
// Reenable the user interaction
// Ex: this.mainPanel.IsEnabled = true;
}
}
You probably should use TPL if your framework version is 4.0:
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext(); // this will work only if you're running this code from UI thread, for example, by clicking a button
Task.Factory.StartNew(() => UnloadData()).ContinueWith(t => /*update ui using t.Result here*/, uiScheduler);
Hope this helps.
You have to implement a callback function (RunWorkerCompleted), this is called when the background worker finishes.
Check out an example here:
http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx

How to avoid spaghetti code when using completion events?

Somehow I cannot believe that I am the first one to run into that problem (and I don't want to believe that I am the only one stupid enough not to see a solution directly), but my search-fu was not strong enough.
I regularly run into a situation, when I need to do a few time-consuming steps one after the other. The workflow looks like
var data = DataGetter.GetData();
var processedData = DataProcessor.Process(data);
var userDecision = DialogService.AskUserAbout(processedData);
// ...
I don't want to block the UI during each step, so every method does return immediately, and raises an event once it has finished. Now hilarity ensues, since the above code block mutates into
DataGetter.Finished += (data) =>
{
DataProcessor.Finished += (processedData) =>
{
DialogService.Finished(userDecision) =>
{
// ....
}
DialogService.AskUserAbout(processedData);
}
DataProcessor.Process(data);
};
DataGetter.GetData();
This reads too much like Continuation-passing style for my taste, and there has to be a better way to structure this code. But how?
The correct way would be to design your components in a synchronous way and execute the complete chain in a background thread.
The Task Parallel Library can be useful for such code. Note that TaskScheduler.FromCurrentSynchronizationContext() can be used to run the task on the UI thread.
Task<Data>.Factory.StartNew(() => GetData())
.ContinueWith(t => Process(t.Result))
.ContinueWith(t => AskUserAbout(t.Result), TaskScheduler.FromCurrentSynchronizationContext());
You can put everything into a BackgroundWorker. The following code would only work properly if you change the methods GetData, Process, and AskUserAbout to run synchronously.
Something like this:
private BackgroundWorker m_worker;
private void StartWorking()
{
if (m_worker != null)
throw new InvalidOperationException("The worker is already doing something");
m_worker = new BackgroundWorker();
m_worker.CanRaiseEvents = true;
m_worker.WorkerReportsProgress = true;
m_worker.ProgressChanged += worker_ProgressChanged;
m_worker.DoWork += worker_Work;
m_worker.RunWorkerCompleted += worker_Completed;
}
private void worker_Work(object sender, DoWorkEventArgs args)
{
m_worker.ReportProgress(0, "Getting the data...");
var data = DataGetter.GetData();
m_worker.ReportProgress(33, "Processing the data...");
var processedData = DataProcessor.Process(data);
// if this interacts with the GUI, this should be run in the GUI thread.
// use InvokeRequired/BeginInvoke, or change so this question is asked
// in the Completed handler. it's safe to interact with the GUI there,
// and in the ProgressChanged handler.
m_worker.ReportProgress(67, "Waiting for user decision...");
var userDecision = DialogService.AskUserAbout(processedData);
m_worker.ReportProgress(100, "Finished.");
args.Result = userDecision;
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs args)
{
// this gets passed down from the m_worker.ReportProgress() call
int percent = args.ProgressPercentage;
string progressMessage = (string)args.UserState;
// show the progress somewhere. you can interact with the GUI safely here.
}
private void worker_Completed(object sender, RunWorkerCompletedEventArgs args)
{
if (args.Error != null)
{
// handle the error
}
else if (args.Cancelled)
{
// handle the cancellation
}
else
{
// the work is finished! the result is in args.Result
}
}

Categories

Resources