Stop startActivity(intent) when going in catch block from another class - c#

I am developing an Android Xamarin appliation in which I have an activity with a button. Some of the code in the button is this:
fsp_SellDet_New_ByItemID fsp_SellDet_New_ByItemID = new fsp_SellDet_New_ByItemID(this);
fsp_SellDet_New_ByItemID.ExecuteNonQuery(_SellID,
_ItemID,
_PodID,
_ItemSellQty,
_ItemPrice,
_ItemPricePer,
-_BaseDiscount,
-_AdditionalDiscount,
_ItemSum,
_ItemVAT,
_ItemCode,
_ItemShortName,
_ItemBrand,
_ItemIssue);
Intent i = new Intent(this, typeof(SellDet));
StartActivity(i);
Finish();
My problem is that inside the ExecuteNonQuery method I have handled exceptions in a try and a catch block like so:
catch (Exception ex)
{
_dlgAlert = new AlertDialog.Builder(this).Create();
_dlgAlert.SetMessage(ex.Message);
_dlgAlert.SetTitle(Resources.GetString(Resource.String.Error));
_dlgAlert.SetButton("OK", delegate { });
_dlgAlert.Show();
return;
}
Even tho I am using "return;", Android still opens the next activity so I cannot really see what the exception was, since by the time the AlertDialog shows up, the next activty is already opened.
Can you give me some advices on how to make it so if I receive an exception in the ExecuteNonQuery method, an AlertDialog will popup and it won't go in the next activty.
Or maybe can you tell me how to make it, so that you will have to press "OK" on the alertDialog and then it will go in the activty. Remember, the AlertDialog is inside the executeNonQuery method in the newly created class, not in the button method..
Thank you in advance

There are many ways to fix this issue. In no particular order (let me know if you need to see coded examples for any of them):
Do not catch the exception in ExecuteNonQuery() and instead catch it within the calling method
Have ExecuteNonQuery() return a bool, false if an exception occurs and true if not. Then put an if check around your StartActivity code
Pass an Action into your ExecuteNonQuery() that would run within the empty delegate you are passing to _dlgAlert.SetButton("OK", delegate { /* Passed in Action executes here */ });, the Action would have your StartActvity code in it

Related

Where was call made so I can manage exception?

I have a webform with button ButtonAdd. I click on ButtonAdd and event handler ButtonAdd_Click() is invoked.
This sequence of events breaks in ClassX, and has method ReturnResults() that looks like this:
public DataTable ReturnResults(string ConnectionString, string Employee)
{
DataSet projects = new DataSet();
string sqlSelect = string.Format("usp_ReturnEmplData '{0}'", Employee);
try
{
nsbProject = SqlHelper.ExecuteDataset(ConnectionString, CommandType.Text, sqlSelect);
}
catch (SqlException e)
{
throw;
}
DataTable empTable = projects.Tables[0];
return empTable;
}
ReturnResults() is not called directly from the webform, but I don't know who exactly called this method.
So now the debugger hits throw;, pressing F11 ("step into") takes me to the web browser with the unmanaged error.
I assumed that by throwing the exception the debugger would take me to the previous class that called ClassX.ReturnResults(), and so on, until reaching the webform. But that's not happening. As soon as throw; is hit, I get the unhandled error in the webform, and that's exactly what I want to avoid.
My question is: how can I see all the calls (between ButtonAdd_Click() to ReturnResults without having to debug the button click?
As Kenneth K mentioned, looking at the stack trace in the exception object will display all the previous calls made to reach the call where the call was made.
Something that I just realized is that the last method was the only one with the try-catch statement, which means that throwing or rethrowing the exception will do no good since the previous call did not have try-catch statement.

will this cause a memory leak in C#

I am learning C# again after a whole lot of years. I did C# programming back in the 2.0 days. The language has indeed evolved, and its fantastic. That being said, I am making a W8/WP8 universal app. Basically when the app launches, the constructor runs a method. This method checks for a connection and if the connection is enabled, the program flows forward.
private async void UpdateInformationSection(IUICommand command) {
InformationModel GeneralInformationModel = new InformationModel
{
apistatus = await voip_service.isAPIEnabled(),
apimessage = await voip_service.GetAPIMessage(),
currentbalance = await voip_service.getBalance(),
currentip = await voip_service.getIP()
};
if (GeneralInformationModel.apistatus == false) {
var msgdialog = new MessageDialog(
"Please go to voip.ms to enable your API. You will need to know the IP address of the device on which this application is installed",
"API connection could not be established");
// Add commands and set their callbacks; both buttons use the same callback function instead of inline event handlers
msgdialog.Commands.Add(new UICommand(
"Try again", new UICommandInvokedHandler(this.UpdateInformationSection)));
// Show the message dialog
await msgdialog.ShowAsync();
}
// set the data context for the first section of the hub
// so we can use bindings.
mainpagehub.Sections[0].DataContext = GeneralInformationModel;
So if you notice, if the connection fails then we have a message dialog popped up. There is a "try again" button the popup. When users click this button, it has a "callback function" associated with it (new stuff to me, I guess its like an event handler?). Anyways, instead of coding a new method, I made the callback method the same as the current method the messagebox is executed in. So basically what I did was added an argument so I have this UpdateInformationSection(IUICommand command). And then the callback function is the same method.
What I am scared of: Everytime they click the "try again" button, will it destroy the old instance of it? In other words, when they click the "try again" button, does the method finish executing? Otherwise I am imagining a scenario where the method is called again and again and each method is stuck in limbo (if this makes any sense).
Also, in my constructor when the method is FIRST called ,I had to change it to
//Update HUB Sections.
// send null as argument since its not coming from a "command button"
// the argument is required when the API connection cant be established
// and thus a modal dialog comes up with a "try again" command button.
UpdateInformationSection(null);
Is it okay sending a "null" like that to the "command" argument? What is the right procedure here.
For sure, there's no true recursion here, because you are using async. But it is possible (probable, actually, but I haven't double-checked) that the MessageDialog does not complete the ShowAsync() method call until your own command delegate completes. This would result in the multiple instances of MessageDialog remaining reachable until you finally don't show it, preventing them from being garbage-collected (i.e. the closest you can get to a real memory leak with managed objects).
IMHO, the method would be better-implemented if you avoided this potential re-entrancy, by queuing the method for execution again instead of call it directly. That could look something like this:
private async void UpdateInformationSection(IUICommand command) {
InformationModel GeneralInformationModel = new InformationModel
{
apistatus = await voip_service.isAPIEnabled(),
apimessage = await voip_service.GetAPIMessage(),
currentbalance = await voip_service.getBalance(),
currentip = await voip_service.getIP()
};
if (GeneralInformationModel.apistatus == false) {
var msgdialog = new MessageDialog(
"Please go to voip.ms to enable your API. You will need to know the IP address of the device on which this application is installed",
"API connection could not be established");
// Add commands and set their callbacks; both buttons use the same callback function instead of inline event handlers
msgdialog.Commands.Add(new UICommand("Try again"));
// Show the message dialog
await msgdialog.ShowAsync();
var _ = CoreWindow.GetForCurrentThread().Dispatcher
.RunAsync(CoreDispatcherPriority.Normal,
() => { var ignoreTask = UpdateInformationSection(command); });
return;
}
// set the data context for the first section of the hub
// so we can use bindings.
mainpagehub.Sections[0].DataContext = GeneralInformationModel;
This way, each time the MessageDialog is displayed, it's given the opportunity to go ahead and close before you redisplay it.
The above assumes "Try again" really is the only option you present. Of course, if you have additional options, you can use the UICommand object to distinguish between the selected option and do the appropriate thing; "Try again" would do the above call to RunAsync() the method again, while other options would do whatever they do.
All that said, personally I think it would be better to avoid this pattern. Presumably, the user did something else that originally initiated this dialog. At the very least, there ought to also be a "Cancel" option as an alternative to "Try Again". And IMHO it would actually be better to just present this as an alert with the default "Close", so that the user simply is taken back to wherever they were, so that after they fix the configuration issue, they can just explicitly attempt the action/operation again.
I'm of course making some assumptions about the program here. Lacking specific details, I admit there could be some compelling reason to do it the way you are now instead. But at least be sure this is really the best way to do it. Sticking a user in a potentially endless loop seems a bit "off" to me. :)
EDIT:
To elaborate on this bit of code:
var _ = CoreWindow.GetForCurrentThread().Dispatcher
.RunAsync(CoreDispatcherPriority.Normal,
() => { var ignoreTask = UpdateInformationSection(command); });
The RunAsync() method causes the given delegate to be executed in the Dispatcher's thread, i.e. the UI thread for your program. This is where the method is already (presumably) running, since it's a command invoked by some UI object. Doing it this way allows the method to be re-invoked, but in a non-re-entrant way. I.e. the current method call is allowed to complete and return before the next one starts. This eliminates any recursive aspect.
The invoked delegate itself — () => { var ignoreTask = UpdateInformationSection(command); } — using the statement body lambda syntax, is simply the method call to invoke your command method again.
Finally, both the RunAsync() method and your command method are async methods, returning a Task instance. In this particular case, we don't need to wait for them to finish, so there's no await, but if we don't do something with the return value the compiler will generate a warning. For me, the easiest, cleanest way to suppress the warning is to go ahead and copy the Task reference to a local variable, which is enough to make the compiler happy. The RunAsync() method is copied to a variable named _, which is what I usually use for variables that I don't actually need to use, while the command method's return value is copied to a variable named ignoreTask, named that way to be explicit about the purpose of the variable (which is to ignore the Task returned from your command method).

Exit Method without ArgumentException

i have a Cancel button on a Progressbar, which is used to Show the Progress of Uploading e-Mails,
now i want this button to Exit the method which Uploads e-Mails.
My plan, once the button gets pressed, make bool cancelUpload true.
i have been unlucky to exit the method with the use of break or simply through an if Statement.
but now i found online that i could throw an Argument Exception,
which i implemented as follows:
if (cancelUpload)
{
throw new ArgumentException("SomeText");
}
but the Problem i have with this, is that once the User clicks on Cancel, he gets an Exception, which Looks like an Error or something went wrong, is there a way to get out of the method, without it looking as though something went wrong?(similiar to ArgumentException)
Thanks a lot in Advance!
Edit: The Method (void Method) is to big to be shown,
but when i tried to return;, i got an Error in Visual Studio saying:
TargetInvocationException was unhandled Exception has been thrown by the target of invocation

Error in CanExecute() - how to get rid of dialog?

I'm trying to handle exceptions in a dialog so that if any exception occurs, the dialog will be closed and the application will not crash. As you can see, I use a simple try-catch block:
IDialogView dialog = null;
try
{
if (_dialogViewModel == null)
{
dialog = ViewFactory.SomeDialog();
_dialogViewModel = new DialogViewModel(dialog);
_dialogViewModel.LoadData();
}
_dialogViewModel.ShowDialog();
}
catch (Exception ex)
{
if (dialog != null)
dialog.Close();
_dialogViewModel = null;
MessageBox.Show("Sorry, there was an error in the dialog.", "Error",
MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
The problem happens when an error occurs in button's CanExecute() event handler. Error is successfully caught, but when I show the MessageBox to the user, CanExecute() executes again, and so the error happens again. In the end it results in application crash.
I've googled some info, and it were said to make sure that there is no exceptions in CanExecute() event handler. But something like this can happen somewhere else, and that's why I want to simply catch ALL exceptions in the dialog entry point without working with every method.
So, my question is: how to destroy the dialog so that after exception catch it won't show again anymore? Close() didn't work, because before closing it still calls CanExecute().
As you found when you googled, you should make sure that a CanExecute handler is a) lightweight and b) never throws an exception. You are running into the main reason for this: a CanExecute will be run repeatedly, and automatically, by the framework. It will run when focus changes, on input events, when databindings change, and in response to a number of other reasons that you have little to no control over.
The problem is: you do have an error, and that error is occurring repeatedly. That means you can choose between crashing, or showing the dialog repeatedly. Or, you can do something about the error.
Your answer: fix the error.
(Your handler as it stands is fine for your other errors. Leave it there. But this particular error, you need to fix right away.)

Why does throw crash my program but return doesn't?

I am trying to catch exceptions for my form client not being able to establish a connection to a server with this in the Connect callback:
try
{
client.EndConnect(async);
}
catch (Exception e)
{
client.Close();
return;
}
This works fine but this behavior is encapsulated in to a class so I want to call throw; instead of return; so that the client class can handle it instead, like so:
try
{
client.Connect(host, port);
}
catch
{
Console.WriteLine("Could not connect to: " + host + ":" + port.ToString());
}
So why not just call throw; then? Well, for some reason if I call throw;, throw new Exception();, or basically anything other than return; the program failsfast. I'm really not sure what's causing this. I tried removing client.Close(); to see if it was the problem but nothing. If I don't call return; the program just immediately exits with no error.
Anyone know what's going on here?
Edit: I do not understand why I am getting downvoted so much. I showed how I am attempting to catch these exceptions and am asking why they are not working properly. I think the problem may be (not sure, just came up with this) because within the asynchronous callback, because it is a new thread in the ThreadPool, calling throw; does not do anything because, because it is not synchronous, there is nothing to throw back to and the application dies. Even with this knowledge, I am not sure how to solve this problem unless I put some sort of try-catch on the entire program.
I suppose a solution could be just sticking with return; because there is nothing to throw back to (due to the asynchronous callback nature of the method) and instead raise an event indicating a failure of connection. Regardless, many thanks for the downvotes and helping me solve this problem. Oh wait...
What's happening is that the EndConnect is not happening on the same thread as your BeginConnect. When EndConnect throws an exception, it is caught by the worker thread's unhandled exception handler, which fails fast (the other option is that it gets ignored and you never find out that your code isn't working).
You have to come up with a way to tell your main form thread that the connect failed.
As others have pointed out, you'll need to catch your exception one way or another to avoid program termination.
For some ideas on how you can do that "globally", see How to catch ALL exceptions/crashes in a .NET app. Whether this is actually a good idea depends on the specific needs of your program...
Relevant for WinForms:
Can't tell based on your question alone, but in case this is actually a WinForms application, you may need to be cognizant of the difference in behavior of modal forms that throw exceptions, depending on whether the debugger is active or not. Let's say we have two forms - the second one is shown as a modal child of the first one:
If application was started through debugger, second form is closed and and stack unwinding goes all the way to the first form's catch block (if any).
If application is started outside debugger, stack unwinding stops before second form is closed and generic exception message is displayed. The second form stays open and catch block in the first form is never reached.

Categories

Resources