I have written an application that uses background workers for long running tasks. At times, after the task is completed, the application will freeze. It doesn't do it right away, it will do it after the application sits idle for a little bit of time.
To try to find out where it is hanging, in my development environment I ran it and waited for it to freeze. I then went to Debug > Break All. It is hanging in the Main() method in Program.cs:
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Main());
}
}
The Application.Run line is highlighted as where the application is hung. When I hover my cursor over the carat in the left border I get a tool tip saying "This is the next statement to execute when this thread returns from the current function."
In looking at this code I realized that it is calling the "main" form of the application, which I named "Main." So my first question is does this matter since the current method is named "Main" also? If so, what are the ramifications of renaming the form, if that is possible?
If that is not an issue, then it would go back to the background worker I would imagine. The application never freezes if those long running tasks are never ran. I know that you should never try to access the UI thread from a background worker thread and I don't think I'm doing that but here is some code that hopefully someone may spot something:
First I start the thread from the UI thread passing in an argument:
bgwInternal.RunWorkerAsync(clients)
In the DoWork method it calculates and creates invoices for the passed in argument (clients). It creates PDF files and saves them to disk. None of that work tries to access the UI. It does use the ProgressChanged event handler to update a progress bar and a label in the UI:
private void bgwInternal_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pgbProgress.Value = e.ProgressPercentage;
lblProgress.Text = e.ProgressPercentage.ToString();
}
And finally the RunWorkerCompleted event handler:
private void bgwInternal_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show("Error occurred during invoice creation.\n\r\n\rError Message: " + e.Error.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else if (!e.Cancelled)
{
MessageBox.Show("Invoice Creation Complete", "Complete", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show("Invoice Creation Cancelled", "Cancelled", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
btnCreateInv.Enabled = true;
btnClose.Enabled = true;
btnCancel.Enabled = false;
}
Could it be hanging because I'm accessing UI elements in this event handler?
One final note, I was using Application.DoEvents():
while (bgwInternal.IsBusy)
{
Application.DoEvents();
}
But I commented that out to see if it would make a difference and it did not.
Not having a lot of multithreading experience I chose to use background worker threads because they are simple and straightforward. Other than using Debug > Break All I really don't know how to track down the exact reason this is happening.
Any thoughts / ideas would be greatly appreciated.
Thanks.
Related
I am showing activity indicator after clicking login button until redirecting the user to another page, to make them understand some progress is going on. But after clicking login button Activity Indicator is not shown immediately, it is shown after few seconds,
Why its so? To reduce that delay only I am putting activity indicator...
My Code:
async void loginButtonGesture_Tapped(object sender, EventArgs e)
{
Device.BeginInvokeOnMainThread(() =>
{
loadingPanel.IsRunning = true;
loadingPanel.IsVisible = true;
});
}
Does the method have to be async void? It seems like this particular scheduling anything on the main thread shouldn't need to be async. Try that to see if it changes anything. Also you could try to set breakpoints on the Device.BeginInvokeOnMainThread line, and the loadingPanel.IsRunning... line to see where the delay happens.
First of all, loginButtonGesture_Tapped() event handler is triggered by UI thread so you don't need to use Device.BeginInvokeOnMainThread(), it is already in UI thread. But since you used Device.BeginInvokeOnMainThread() here, the reason for the delay is because on Android, your code inside of BeginInvokeOnMainThread() is added to MainLooper's message queue,(your code is not executed immediately) and is executed when the UI thread is scheduled to handle its messages.
The detailed answer can be found in Xamarin document:
For iOS:
IOSPlatformServices.BeginInvokeOnMainThread() Method simply calls NSRunLoop.Main.BeginInvokeOnMainThread
public void BeginInvokeOnMainThread(Action action)
{
NSRunLoop.Main.BeginInvokeOnMainThread(action.Invoke);
}
https://developer.xamarin.com/api/member/Foundation.NSObject.BeginInvokeOnMainThread/p/ObjCRuntime.Selector/Foundation.NSObject/
You use this method from a thread to invoke the code in the specified object that is exposed with the specified selector in the UI thread. This is required for most operations that affect UIKit or AppKit as neither one of those APIs is thread safe.
The code is executed when the main thread goes back to its main loop for processing events.
For Android:
Many People think on Xamarin.Android BeginInvokeOnMainThread() method use Activity.runOnUiThread(), BUT this is NOT the case, and there is a difference between using runOnUiThread() and Handler.Post():
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);//<-- post message delays action until UI thread is scheduled to handle messages
} else {
action.run();//<--action is executed immediately if current running thread is UI thread.
}
}
The actual implementation of Xamarin.Android BeginInvokeOnMainThread() method can be found in AndroidPlatformServices.cs class
public void BeginInvokeOnMainThread(Action action)
{
if (s_handler == null || s_handler.Looper != Looper.MainLooper)
{
s_handler = new Handler(Looper.MainLooper);
}
s_handler.Post(action);
}
https://developer.android.com/reference/android/os/Handler.html#post(java.lang.Runnable)
As you can see, you action code is not executed immediately by Handler.Post(action). It is added to the Looper's message queue, and is handled when the UI thread's scheduled to handle its message.
I have a process that takes a long time to finish executing, the user should be able to see a simple feedback when the process starts and finishes
something like this:
protected async void Button1_Click(object sender, EventArgs e)
{
TextBox1.Text = "Process started..\n";
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
await ProcessDelay();
sw.Stop();
TextBox1.Text += "Process finished.\n";
TextBox1.Text += "Elapsed Time (ms): " + sw.ElapsedMilliseconds.ToString() + "\n";
}
private async Task ProcessDelay()
{
await Task.Delay(5000);
}
Text value in TextBox is not updated until the execution of ProcessDelay() is done. What am I missing here?
Remember that when you're working with ASP.NET, you are working within a strict request+response paradigm. WebForms tries to hide this from you, but it's still one-response-per-request underneath. So, when you click a button in your browser, it sends a request to the web server, which executes the click code, returning a result. It can only return one result. So there's no way it can, say, make a change to part of the page and then later make another change.
To put it another way, async on ASP.NET yields to the ASP.NET runtime (that is, it returns the request thread to the thread pool). It does not yield to the browser (that is, it does not return a response).
To do what you want, you'll need an alternative technology. If the background work doesn't take too long, you could consider SignalR. Otherwise, you'll probably need a proper distributed architecture: a reliable queue connected to an independent background process. I describe a few approaches on my blog.
I've got a piece of code that looks like this:
public void Foo(int userId)
{
try {
using (var tran = NHibernateSession.Current.BeginTransaction())
{
var user = _userRepository.Get(userId);
user.Address = "some new fake user address";
_userRepository.Save(user);
Validate();
tran.Commit();
}
}
catch (Exception) {
logger.Error("log error and don't throw")
}
}
private void Validate()
{
throw new Exception();
}
And I'd like to unit test if validations ware made correctly. I use nunit and and SQLLite database for testing. Here is test code:
protected override void When()
{
base.When();
ownerOfFooMethod.Foo(1);
Session.Flush();
Session.Clear();
}
[Test]
public void FooTest()
{
var fakeUser = userRepository.GetUserById(1);
fakeUser.Address.ShouldNotEqual("some new fake user address");
}
My test fails.
While I'm debugging I can see that exception is thrown, Commit has not been called. But my user still has "some new fake user address" in Address property, although I was expecting that it will be rollbacked.
While I'm looking in nhibernate profiler I can see begin transaction statement, but it is not followed neither by commit nor by rollback.
What is more, even if I put there try-catch block and do Rollback explicitly in catch, my test still fails.
I assume, that there is some problem in testing environment, but everything seems fine for me.
Any ideas?
EDIT: I've added important try-catch block (at the beginning I've simplified code too much).
If the exception occurs before NH has flushed the change to the database, and if you then keep using that session without evicting/clearing the object and a flush occurs later for some reason, the change will still be persisted, since the object is still dirty according to NHibernate. When rolling back a transaction you should immediately close the session to avoid this kind of problem.
Another way to put it: A rollback will not rollback in-memory changes you've made to persistent entities.
Also, if the session is a regular session, that call to Save() isn't needed, since the instance is already tracked by NH.
I am very new to Workflow Foundation development, and am worried that I am opening serious holes in our business process handling by not properly handling application / database exceptions in custom activities.
I would appreciate some steps that I could take to add this resiliency to my custom activities so that I can easily use the designer and other tools to ensure that, as far as I can, I do not create custom activities that are brittle and likely to cause workflow cleanup issues.
Here are some options, at different execution stages, that are available for you to use to handle exceptions.
First option (at activity/workflow execution time):
First of all, on custom activities, you should always try to treat exceptions inside it's execution. Some activities might not work but the overall workflow can continue and, in such cases, log the error to persistence and even show the user that something didn't work as expected but the thing will continue are good options.
That being said there'll always be cases where an activity have to (and even should) thrown exceptions and those should be treated at workflow level. Something like: if this exception occurs on this activity, do this, otherwise, do that.
Lets imagine you've a custom activity which persists something to DB:
public sealed PersistIntegerToDb : CodeActivity
{
public InArgument<int> ValueToPersist { get; set; }
protected override void Execute(CodeActivityMetadata metadata)
{
try
{
// persist
}
catch(SqlException exception)
{
// re throws the SqlException
throw new SqlException("'ValueToPersist' wasn't persisted.", exception);
}
}
}
Then, in your code or through designer you've available TryCatch activity to catch that error and treat it the way you want:
var workflow = new TryCatch
{
Try = new PersistIntegerToDb
{
ValueToPersist = 10
},
Catches =
{
new Catch<SqlException>
{
Action = new ActivityAction<SqlException>
{
Handler = new WriteLine
{
Text = "An error occurred and the value wasn't saved! Anyway workflow will continue..."
}
}
}
}
}
Or you can terminate it using TerminateWorkflow.
Second option (at design time):
Ok, but you can argue that client doesn't know that he have to handle those cases. In that case, and this is an usability option you might consider, instead of making available PersistIntegerToDb on the designer, you can provide an activity already surrounded by exceptions catches to handle, through IActivityTemplateFactory:
public sealed PersistIntegerToDbFactory : IActivityTemplateFactory
{
public Activity Create(DependencyObject target)
{
return new TryCatch
{
Try = new PersistIntegerToDb
{
ValueToPersist = 10
},
Catches =
{
new Catch<SqlException>
{
}
}
};
}
}
Now you just add PersistIntegerToDbFactoryas if it were a regular activity:
new ToolboxItemWrapper(typeof(PersistIntegerToDbFactory), null, "Persist Integer");
Third option (at validation time):
Never forget to validate workflow before execution!
var validationResults =
ActivityValidationServices.Validate(workflow);
foreach(var error in validationResults.Errors)
{
Console.WriteLine(string.Format(
"Validation error '{0}', generated on activity '{1}' in the property named {2}",
error.Message,
error.Source.DisplayName,
error.PropertyName));
}
Fourth option (at application execution time):
You can handle all not treated exception that might happen during execution, using OnUnhandledException event:
var wfApp = new WorkflowApplication(activity);
wfApp.OnUnhandledException +=
delegate(WorkflowApplicationUnhandledExceptionEventArgs e)
{
if (e.UnhandledException is SqlException)
{
Console.WriteLine("Some data wasn't properly persited.");
}
else
{
Console.WriteLine("Unknown error: " + e.UnhandledException.GetType());
Console.WriteLine("With message: " + e.UnhandledException.Message);
}
Console.WriteLine("Ok, workflow will be abort");
return UnhandledExceptionAction.Abort;
};
Note that, at this stage, you can only Abort, Cancel and Terminate the workflow and that's the reason why you should 1) avoid throwing exceptions or 2) treat exceptions inside your workflow. OnUnhandledException is your last chance to end the workflow execution gracefully and should always be treated even if for logging purposes. Something like DivideByZeroExceptions can occur and are almost impossible to predict and catch at validation time, for example.
As far as custom activities goes you should treat them as any other piece of code. Handle the errors you can and let you can't handle the rest bubble up.
At the workflow level you can use the TryCatch activity and workflow persistence to deal with errors. Specially persistence is something people overlook often. Add Persist activities at appropriate steps in your workflow and set the workflow to abort on unhandled errors. Now you can go back in and reload the last good workflow state and retry the actions that cause an unhandled exception. A great way of recovering from failures with resources like databases that might be unavailable for some reason and then come back.
Our ASP.NET 2 web application handles exceptions very elegantly. We catch exceptions in Global ASAX in Application_Error. From there we log the exception and we show a friendly message to the user.
However, this morning we deployed the latest version of our site. It ran ok for half an hour, but then the App Pool crashed. The site did not come back up until we restored the previous release.
How can I make the app pool crash and skip the normal exception handler? I'm trying to replicate this problem, but with no luck so far.
Update: we found the solution. One of our pages was screenscraping another page. But the URL was configured incorrectly and the page ended up screenscraping itself infinitely, thus causing a stack overflow exception.
The most common error that I have see and "pool crash" is the loop call.
public string sMyText
{
get {return sMyText;}
set {sMyText = value;}
}
Just call the sMyText...
In order to do this, all you need to do is throw any exception (without handling it of course) from outside the context of a request.
For instance, some exception raised on another thread should do it:
protected void Page_Load(object sender, EventArgs e)
{
// Create a thread to throw an exception
var thread = new Thread(() => { throw new ArgumentException(); });
// Start the thread to throw the exception
thread.Start();
// Wait a short while to give the thread time to start and throw
Thread.Sleep(50);
}
More information can be found here in the MS Knowledge Base
Aristos' answer is good. I've also seen it done with a stupid override in the Page life cycle too when someone change the overriden method from OnInit to OnLoad without changing the base call so it recursed round in cirlces through the life cycle: i.e.
protected override void OnLoad(EventArgs e)
{
//some other most likely rubbish code
base.OnInit(e);
}
You could try throwing a ThreadAbortException.