So I'm using an if statement and I would assume if that statement doesn't find/do what it's suppose to, then it should throw an exception right? Well for some reason I'm getting absolutely nothing, the if statement isn't working, yet I'm not getting an exception?
Example of code -
try
{
label1.Text = "Finding route";
string sxp = "//*[#id='s']";
if (driver.FindElements(By.XPath("sxp")).Count != 0)
{
driver.FindElement(By.XPath(sxp)).Click();
label1.Text = "sxp done";
}
}
catch
{
CheckRoute();
label1.Text = "Exception thrown";
}
and the response from my program is nothing as soon as it hits the " if " statement, because before that it changes label1 to specified string..
Since you are checking it with if statement it has nothing to do with Exception throw. Remove if and it will throw an exception when it cant find the element. Also access the message with e.Message() if I am not mistaking. In your case it should be ElementNotFoundException.
try
{
label1.Text = "Finding route";
string sxp = "//*[#id='s']";
driver.FindElement(By.XPath(sxp)).Click();
label1.Text = "sxp done";
}
catch(Exception e)
{
CheckRoute();
label1.Text = "Exception thrown";
}
catch(ElementNotFoundException e)
{
Console.WriteLine(e.Message());
}
I think you are confused about ifs and how they work. ifs don't throw exceptions if they don't evaluate to true. Exceptions are thrown in specific cases when something unexpected happens. On example would be if you used driver.FindElement() and the element wasn't found... that would throw an ElementNotFoundException.
In your case, you have done the right thing and used .FindElements() (plural) and because of this, your code will not throw an exception. So, because of this you can remove the try-catch and additional simplifications result in the code below.
label1.Text = "Finding route";
IReadOnlyCollection<IWebElement> routes = driver.FindElements(By.Id("s"));
if (routes.Count > 0)
{
routes.ElementAt(0).Click();
label1.Text = "sxp done";
}
else
{
CheckRoute();
label1.Text = "sxp not found";
}
I stored the resulting collection from the .FindElements() in a variable, routes, so that it can be reused. Your code was hitting the page twice. I removed the try-catch because it was not needed.
Related
I have tried multiple ways for my program to catch an error by using try get for when the user does not enter any data into the text box for one of the text boxes and for the other when the user does not enter exactly 9 numbers into a text block. I am using C# WPF.
I have tried lots of different methods. one that seemed to work is when i converted to an integer, it seemed to catch it for some reason but i am using strings instead. For example
try
{
// remmeber, textboxes always capture the data as a string therefore we need to convert to an integer
CourseDetails.Name = Convert.ToInt32(txtName.Text);
CourseDetails.SCNnumber = Convert.ToInt32(txtSCNnumber.Text);
}
// if something does go wrong with any of the instructions in the try block then we will catch the error rather than crash the program
catch (Exception)
{
MessageBox.Show("Please complete all fields");
return;
}
try
{
if (txtName.Text.Length < 0)
{
MessageBox.Show("Enter your full name");
}
else
{
CourseDetails.Name = txtName.Text;
}
if (txtSCNnumber.Text.Length != 9)
{
MessageBox.Show("SCN number must be 9 characters long");
}
else
{
CourseDetails.SCNnumber = txtSCNnumber.Text;
}
}
catch (Exception)
{
MessageBox.Show("Please complete all fields");
}
The result I'm looking for is when a user inputs data into the first text box for their name it should save to the variable CourseDetails.Name otherwise if they leave it blank the program will catch this as an error an display a message.
for the second text box if the user enters anything other than 9 characters then the program will display an error message stating that the phone number must be more than 9 characters. otherwise the program will save the users input into the variable CourseDetails.SCNnumber
A try-catch block catches exceptions. To catch an exception, an exception has to be thrown. Your first try-catch block will work, because Convert.ToInt32 will throw an FormatException if the input is invalid as documented here.
To make the second try-catch block work, you have to throw an exception on invalid input.
try
{
if (txtName.Text.Length < 0)
{
throw new ValidationException("Please enter user name")
}
// ...
}
catch(ValidationException ex)
{
MessageBox.Show(ex.Message);
}
As you see i catch on a specific exception type. Is it generally bad practise to catch on the Exception type as you may catch exceptions you can't handle proper inside that catch block. Swallowing those can increase the debigging difficulty significantly.
I would also note Exceptions are not the perfect way to perform more complex validation logic, since a throw jumps right to the next matching catch, so not all fields will be validated.
You have to understand what Try-Catch blocks are used for. Their primary role is to handle exceptions in your program. These exceptions can be compiler exceptions which is thrown by the CLR or program code if there is an error in the program. These exceptions need to be handled to prevent crashing of program. C# provides built-in support to handle the exception using try, catch & finally block.
Now in your code, don't show your MessageBox.Show in your Exception block. What this basically means is that only when an exception is thrown, then your MessageBox will display. This exception (in reference to your code) would be if there is an incorrect conversion of Integer of your txtName.Text.
Instead use If-Else conditions in your scenario. For example:
//Try to parse your captured data to Integer
try
{
if(txtName.Text == "" && txtSCNnumber.Text == "")
{
MessageBox.Show("Please complete all fields");
}
else
{
// remmeber, textboxes always capture the data as a string therefore we need to convert to an integer
CourseDetails.Name = Convert.ToInt32(txtName.Text);
CourseDetails.SCNnumber = Convert.ToInt32(txtSCNnumber.Text);
}
}
//If the parse fails, then throw an exception
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
Thanks for your input guys. I decided to leave the Try-Catch out after reading your comments I realised it wasn't fit for what I was trying to do. I kept it simple with If-Else statements as shown below.
if (txtName.Text == "" && txtSCNnumber.Text == "")
{
MessageBox.Show("Please complete all fields");
txtName.Focus();
}
else if (txtSCNnumber.Text.Length != 9)
{
MessageBox.Show("You have entered an invalid SCN number");
txtSCNnumber.Focus();
}
else
{
CourseDetails.Name = txtName.Text;
CourseDetails.SCNnumber = txtSCNnumber.Text;
}
Regarding the duplicated. I can access the Message property but not the Detail property even when I can see is part of the Exception object during debuging. So the question is Why cant access Detail property.
I catch an exception.
catch (Exception ex)
{
string msg = ex.InnerException.InnerException.Message;
// say Exception doesnt have Detail property
// string detail = ex.InnerException.InnerException.Detail;
return Json(new { status = "Fail", message = msg, detail: detail });
}
ex doesnt say anthing
ex.InnerException show same message
ex.InnerException.InnerException. finally some real message, "db table duplicated key"
ex.InnerException.InnerException.Message I can get the message.
But cant get the Detail "the guilty key" even when there is one property Detail
So how can I get the Detail?.
Bonus: Why have to go deep InnerException twice to get some meaningfull message?
I think the most elegant way to do this now is using C# 6 when keyword in a catch statement and C# 7 is operator.
try
{
//your code
}
catch (DbUpdateException ex) when (ex.InnerException is PostgresException pex)
{
string msg = pex.Message;
string detail = pex.Detail;
return Json(new { status = "Fail", message = msg, detail: detail });
}
The trick is to recognize the type of exception being thrown and cast the General Exception to the correct Type where you will then have access to extended properties for that Exception type.
for example:
if (processingExcption is System.Data.Entity.Validation.DbEntityValidationException)
{
exceptionIsHandled = true;
var entityEx = (System.Data.Entity.Validation.DbEntityValidationException)processingExcption;
foreach (var item in entityEx.EntityValidationErrors)
{
foreach (var err in item.ValidationErrors)
returnVal.Invalidate(SystemMessageCategory.Error, err.ErrorMessage);
}
}
else if (processingExcption is System.Data.SqlClient.SqlException && ((System.Data.SqlClient.SqlException)processingExcption).Number == -2)//-2 = Timeout Exception
{
exceptionIsHandled = true;
returnVal.Invalidate(SystemMessageCategory.Error, "Database failed to respond in the allotted time. Please retry your action or contact your system administrator for assistance.",
messageCode: Architecture.SystemMessage.SystemMessageCode.DBTimeout);
}
The fact that the detail you are looking for is 2 inner exceptions deep is incidental. Depending on how many times the exception is caught and wrapped will determine how deep the exception you care about is - your best bet is to iterate through the exception stack looking for exception types you wish to handle.
Referring to your own answer I commented, you definitely should be much more defensive, otherwise you risk of a null reference exception from within your catch clause.
catch (Exception ex)
{
string Detail = string.Empty;
while ( ex != null )
{
if ( ex is Npgsql.NpgsqlException )
{
// safe check
Npgsql.NpgsqlException ex_npg = (Npgsql.NpgsqlException)ex;
Details = ex_npg.Detail;
}
// loop
ex = ex.InnerException;
}
// warning, Detail could possibly still be empty!
return Json(new { status = "Fail", detail = Detail });
}
You cannot get details more than found in this exception
To show real exception loop over innerexceptions until it is null. Then you reached the first one
The exception was thrown from a source class or function then readed by upper level class that throw it with more global details because there is no error handling on the source
Well, it's very sad, but the inner exception is not a magic stick. Usually it's just an object that author of the code that you call puts as the second parameter of the Exception constructor. So, the general answer: "no way". But debugger sometimes could help :). I would say - call stack of the exception usually more descriptive the InnerException.
A quick solution would be to click on the "Detail" property in the "Quick Watch" window. Your answer will be in "Expression" texbox at the top of the quick watch window. Example, the expression for Postgres duplicate detail is:
((Npgsql.PostgresException)ex.InnerException.InnerException).Detail
Here is my function to get some more info from Postgres exception
catch (Exception ex) {
// Get PGSQL exception info
var msg = ExceptionMessage (ex);
}
public static string ExceptionMessage (Exception ex) {
string msg = ex.Message;
var pgEx = ex as PostgresException;
if (pgEx != null) {
msg = pgEx.Message;
msg += pgEx.Detail != null ? "\n"+pgEx.Detail.ToStr() : "";
msg += pgEx.InternalQuery != null ? "\n"+pgEx.InternalQuery.ToStr() : "";
msg += pgEx.Where != null ? "\n"+ pgEx.Where : "";
}
return msg;
}
Thanks Maciej
this solution is great to intercept PostgreSQL Errors
Only correction I did on this
msg += pgEx.Detail != null ? "\n"+pgEx.Detail.ToStr() : "";
msg += pgEx.InternalQuery != null ? "\n"+pgEx.InternalQuery.ToStr() : "";
instead
msg += pgEx.Detail != null ? "\n" + pgEx.Detail.ToString() : "";
msg += pgEx.InternalQuery != null ? "\n" + pgEx.InternalQuery.ToString() : "";
I have the following situation in code, whats the best way to manage it, the comments contains the situations, and please recommend the best practice.
try
{
string errorMessage = AccountClient.GetAccount(id, out accountDetails);
// FIRST WAY : REMOVE THIS NULL CHECK AT ALL AND LEAVE GetAccountDetails to control
// the Null situation?
if (accountDetails == null)
{
// Second Way: This way? Throw exception here?
throw new ArgumentNullException(nameof(accountDetails));
//Third way? break the function?
break;
}
// GetAccount Details already has null control
Subscription subscription = AccountProcessor.GetAccountDetails(accountDetails);
}
catch (Exception e)
{
throw;
}
First of all, the costruction
catch (Exception e) {
throw;
}
is redundant one and can be eliminated. Now about nulls. There're two
cases:
null is an erroneous value and so it should be signalled
null is an expected, ordinary value and thus it should be proceeded
And so you have (null is an error)
string errorMessage = AccountClient.GetAccount(id, out accountDetails);
// What's wrong: it's id which doesn't correspond to any detail
// (we expect id being s.t. AccountClient.GetAccount(id...) returns not null detail)
if (accountDetails == null)
throw new ArgumentException($"Incorrect id {id} which doesn't have any detail.",
nameof(id));
Subscription subscription = AccountProcessor.GetAccountDetails(accountDetails);
Or (null is an expected outcome)
string errorMessage = AccountClient.GetAccount(id, out accountDetails);
if (accountDetails == null)
return null; // or any reasonable value, or just return, or create new Subscription
Subscription subscription = AccountProcessor.GetAccountDetails(accountDetails);
If you can do anything about null input then handle it.
try
{
string errorMessage = AccountClient.GetAccount(id, out accountDetails);
if (accountDetails == null)
{
// do something about it. Maybe write some logs, substitute with a default value
// or throw appropriate exception ...
}
Subscription subscription = AccountProcessor.GetAccountDetails(accountDetails);
}
catch (Exception e)
{
throw;
}
if you can't then let GetAccountDetails decide what should happen.
try
{
string errorMessage = AccountClient.GetAccount(id, out accountDetails);
Subscription subscription = AccountProcessor.GetAccountDetails(accountDetails);
}
catch (Exception e)
{
throw;
}
Also there is no need to catch an exception, doing nothing and then throw it so you can remove the whole try catch block.
It depends on where this ID is coming from. If the user typed the ID, then I wouldn't generate an Exception, since it is not a error in your program. Just treat the user input and show a proper message. Exceptions are costly, so I usually use them only when i have a real programa failure. Besides that, if you write a custom Exception Handler, it wouldn`t make sense to log a error caused by wrong user input. So i would make it like this:
if (AccountClient.AccountExists(id))
{
AccountDetails details = AccountClient.GetAccount(id);
Subscription subscription = AccountProcessor.GetAccountDetails(accountDetails);
}
Anyway, its good to treat the input on the same way, even if you had treated like above, in case there is any other non treated call to it:
public AccountDetails GetAccount(int id)
{
if (Exists(id))
GetTheAccount(id);
else
throw new Exception(String.Format("Account {0} doesn't exists", id));
}
In this case I would use an Exception because it could really represent an error, if the caller function is passing a wrong value, for instance.
so currently i am writing a program something like this:
try
{
mainprocessing();
}
catch (exception e)
{
//first catch block.
//do something here
}
mainprocessing()
{
try
{
string value = ReadCell.ReadCellValue(allEmployeeTimesheet[i], "Sheet1", "A1"); //I am calling ReadCellValue() method to check the value of A1 cell of an excel spreadsheet and if it is null, it will be handled in the following catch block.
}
catch (NullReferenceException e)
{
//second catch block
//something here to handle it
}
}
But when I run the program now, if string value is null, the exception will be handled in the first catch block. However I want it to be handled in the second catch block. Is there any way to manipulate this?
Didn't read the question the proper way, was thinking you want to get explicit into the top level exception.
When a value is null and trying to access this variable, there will be no reference to an actual object and so an NullReferenceException will be thrown but in this case you are allocating value to an reference so there is another exception thrown rather than NullReferenceException.
The only way to found out which Exception is been thrown, add another catch block below the NullReferenceException.
catch (NullReferenceException e)
{
//second catch block
//something here to handle it, LOG IT!
}
catch (Exception exception)
{
Type exceptionType = exception.GetType();
}
When an Exception has been handled(catched) by the program it returns to the point where this function has been invoked, in this case 'mainprocessing'.
If you explicit WANT to get into the most top level Exception handling block, just throw a new Exception inside the catch, like this:
mainprocessing()
{
try
{
string value = ReadCell.ReadCellValue(allEmployeeTimesheet[i], "Sheet1", "A1"); //I am calling ReadCellValue() method to check the value of A1 cell of an excel spreadsheet and if it is null, it will be handled in the following catch block.
}
catch (NullReferenceException e)
{
//second catch block
//something here to handle it, LOG IT!
throw new Exception("top level exception");
}
}
As mentioned in the comments handling exceptions is not the way to handle flow control in C#. You use them if something unexpected happens, something you are not able to check in advance, before starting your process (e.g. file is corrupted and your read is aborted unexpectedly).
In your case just go with simple if check:
string value = ReadCell.ReadCellValue(allEmployeeTimesheet[i], "Sheet1", "A1");
if (string.IsNullOrWhiteSpace(value))
{
// Handle the null/empty string here.
// From what you said probably the logic you wanted to use in your second catch block.
}
EDIT:
To handle the exception on the level of ReadCell just check if it's null before accessing the value. Then you have a couple of options. You can abort the execution (return) or try to get an instance of ReadCell.
if (ReadCell == null)
{
// abort the execution, create
}
string value = ReadCell.ReadCellValue(allEmployeeTimesheet[i], "Sheet1", "A1");
Alternatively just indent several ifs:
if (ReadCell != null)
{
string value = ReadCell.ReadCellValue(allEmployeeTimesheet[i], "Sheet1", "A1");
if (string.IsNullOrWhiteSpace(value))
{
// Handle the null/empty string here.
// From what you said probably the logic you wanted to use in your second catch block.
}
}
else
{
// Handle null case for ReadCell.
}
Here's how you should handle exceptions in your specific scenario:
private void btnDataStuff_Click(object sender, EventArgs e)
{
try
{
ProcessSomeData();
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
MessageBox.Show("Inner exception: " + ex.InnerException.Message);
}
}
private void ProcessSomeData()
{
try
{
// Code where NullReferenceException exception happens
}
catch (NullReferenceException ex)
{
throw new ApplicationException("Data is null!!!", ex);
}
}
This is the proper way to handle and propagate your exceptions. I think this is what you originally wanted to accomplish. If NullReferenceException exception happens in the ProcessSomeData method - it will be propagated as a new exception with Data is null!!! message but it will also keep the original exception because it stores critical information for later debugging (call stack among other things). This way, you can have "nice" error messages in your application for the end user and original exceptions for the programmer to debug if needed.
This is a very simple example though. Please read this to learn best practices when handling exceptions. It's one of the most important aspects of programming that you will (have to) learn - you will eventuall learn it either way but why take the hard path when you can make your life easier from the start.
Also read up on C# coding conventions so you can write quality code from the start.
Other posters hinted that you should validate your data for null instead of catching exceptions and in most cases this is true but in case you still do want to catch some specific exceptions you now know a proper way to do so.
Im trying to stop processing after an exception is found and displayed it to the user but i cant get my code to stop once one has been found...
try
{
//Someting
}
catch (Exception ex)
{
lblerror.Text = (ex.Message);
//// STOP CODE WHEN EXCEPTION IS FOUND SO USER CAN FIX THE CAUSE
}
finally
{
Response.Redirect("//hud/account.aspx");
}
i have tried throw and return commands with no luck. Im new to all of this and i have googled it with no luck... any ideas what im missing ? or maybe i have the wrong idea all together. its a button click event that is tied in with a textbox, when an exception is thrown it will display the error in a label for the user to resolve (too many numbers...etc ). When corrected and the button is clicked again, this time without throwing an exception the users should be redirected. Any help would be great.
not use finally.
try
{
//Someting
Response.Redirect("//hud/account.aspx");
}
catch (Exception ex)
{
lblerror.Text = (ex.Message);
//// STOP CODE WHEN EXCEPTION IS FOUND SO USER CAN FIX THE CAUSE
}
You should not be using exceptions to do validation or flow-of-control. You should simply check the conditions in the code and present a message if the values don't satisfy the conditions.
e.g.
int foo;
if( !Int32.TryParse( something.Text, out foo ) )
{
lblError.Text = "You must enter a number.";
}
else
{
Response.Redirect...
}
You should remove the redirect logic from the finally block. Because finally block always gets executed weather an exception has encountered or not.
Probably you should try something as listed below by #user3401335. He has moved the redirect as the last statement in the try block. Your core logic stays on the top and if it is successful and no exception has encountered then it allows you to redirect. Otherwise it stops you right there with the help of exception code...
You should try as follows:
try
{
//Something
Response.Redirect("//hud/account.aspx");
}
catch (Exception ex)
{
lblerror.Text = (ex.Message);
// STOP CODE WHEN EXCEPTION IS FOUND SO USER CAN FIX THE CAUSE
}
finally
{
// PUT IN SOMETHING HERE THAT YOU WANT ALWAYS TO GET EXECUTED
}
Try this code:
bool iserror = false;
try
{
int a = 0;
int b = 1;
int c = b / a;
Response.Redirect("//hud/account.aspx");
}
catch (Exception ex)
{
lblerror.Text = (ex.Message);
iserror = true;
}
finally
{
if (!iserror)
{
//do something if you want
}
}