On a button click I am saving info to a Sqlite database. I have the command.ExecuteNonQuery() in a try block. I have got everything handled just find if the catch block is caught, but if everything makes it through just fine I want other code to execute that would clear out the values of my EditTexts and set focus. I try putting that code after the ExecuteNonQuery() in my try block, but it still executes before the catch block even if an exception is caught so the values of my edittexts get cleared out before the catch block can even do anything. Same story if I add the code after my try/catch block entirely. The catch block seems to be the last thing executing and by then the values have been cleared and the catch block can't even execute properly. How do I set the values to clear only after the catch block is cleared and no exceptions are thrown?
EDIT: Tried putting it in a finally block but the same thing. Locals window shows both partnumber.Text and partQty.text are blank by the time they get to the catch block. But if I take out the code that clears those fields then both still have their values in the catch block. Is there something special maybe about Sqlite exceptions that would create a timing issue?
try
{
c.ExecuteNonQuery();
partnumber.Text = "";
partqty.Text = "";
partnumber.RequestFocus();
}
catch (SqliteException ex)
{
if (ex.ErrorCode.ToString() == "Constraint")
{
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.SetTitle("Item Duplication");
builder.SetMessage("You have already counted this item. How would you like to proceed?");
builder.SetPositiveButton("Add to Previous", delegate
{
var newQty = Convert.ToInt32(test.currQuantity(partnumber.Text)) + Convert.ToInt32(partqty.Text);
var n = connection.CreateCommand();
connection.Open();
n.CommandText = "Update [Items] Set Quantity = '" + newQty.ToString() + "' Where ItemNmbr = '" + partnumber.Text + "'";
n.ExecuteNonQuery();
Toast.MakeText(this, "Quantity updated to: " + newQty.ToString(), ToastLength.Long)
.Show();
partnumber.Text = "";
partqty.Text = "";
partnumber.RequestFocus();
connection.Close();
return;
});
builder.SetNegativeButton("Override Previous", delegate
{
var n = connection.CreateCommand();
connection.Open();
n.CommandText = "Update [Items] Set Quantity = '" + partqty.Text + "' Where ItemNmbr = '" + partnumber.Text + "'";
n.ExecuteNonQuery();
Toast.MakeText(this, "Quantity updated to: " + test.currQuantity(partnumber.Text), ToastLength.Long)
.Show();
partnumber.Text = "";
partqty.Text = "";
partnumber.RequestFocus();
connection.Close();
return;
});
var dialog = builder.Create();
dialog.Show();
}
else
{
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.SetTitle("Error");
builder.SetMessage(ex.Message.ToString());
var dialog = builder.Create();
dialog.Show();
}
}
You could try putting them in a finally block.
try {/*execute code*/}
catch(System.Exception e){/*handle exceptions*/}
finally {/*clean up regardless if an exception was thrown or not*/}
Place a bool before your "try" block and set it to a value. If you show an alert, set the bool to the opposite value and then proceed based upon that.
bool EverythingIsFine = true;
try{
//Your code
}
catch(Exception){
if(Condition){
EverythingIsFine = false;
ShowRelatedAlerts();
}
}
if(!EverythingIsFine){
//DoMoreStuff
}
Execution inside a try block stops immediately if an exception is thrown. Therefore, the last line of a try block is only executed if no exceptions are raised.
Looks like you have similar code in the catch block, I am pretty sure this is what's being executed and not the code after your Sql Statement that is throwing the error
put a break point after the statement that is throwing the exception and you will see that it's not being hit.
to provide a bit more context to NotMyself's answer
try
{
c.ExecuteNonQuery();
}
catch (SqliteException ex)
{
// at this point the values in the partNumber textbox haven't been cleared out
showAlerts(ex);
}
finally
{
// clear the textbox after the code in the try block
// and the code in the catch block have executed (IF it executed)
partnumber.Text = "";
partqty.Text = "";
partnumber.RequestFocus();
}
Use try-catch-finally:
try
{
// Try something
}
catch (System.IO.IOException e)
{
// Handle exception
}
finally
{
// Some cleanup
}
Related
sorry if its noob question but I am System Administrator, not developer, but willing to learn more :)
I am writing small console application in C# to verify backup files with MD5 hash. I Actually wrote and it works fine, except it counts error files as good because application works after try-catch even if exception is catch. I will paste part of the code with try catch finally block, my question is can I by any chance in "finally" say "if exception is thrown log filename and exception and go to beginning (start calculating next file) else if stream !=null ....continue Computing hash?
Thank you very much
Ervin
Here is my code in try-catch-finally block
try
{
myHash = null;
myFileMd5 = null;
stream = new FileStream(myFilename, FileMode.Open);
}
catch (FileNotFoundException)
{
File.AppendAllTextAsync(hashList, "The file " + myFilename + " or directory cannot be found." + "\n");
badcounter++;
}
catch (DirectoryNotFoundException)
{
File.AppendAllTextAsync(hashList,"The file " + myFilename + "or directory cannot be found." + "\n");
badcounter++;
}
catch (DriveNotFoundException)
{
File.AppendAllTextAsync(hashList, "The drive specified in 'path' is invalid." + "\n");
badcounter++;
}
catch (PathTooLongException)
{
File.AppendAllTextAsync(hashList, "'path' exceeds the maximum supported path length." + "\n");
badcounter++;
}
catch (UnauthorizedAccessException)
{
File.AppendAllTextAsync(hashList, "You do not have permission to access this file: " + myFilename + "\n");
badcounter++;
}
catch (IOException e) when ((e.HResult & 0x0000FFFF) == 32)
{
File.AppendAllTextAsync(hashList, myFilename + " " + "Sharing violation." + "\n");
badcounter++;
}
catch (IOException e) when ((e.HResult & 0x0000FFFF) == 80)
{
File.AppendAllTextAsync(hashList, myFilename + " " + "The file already exists." + "\n");
badcounter++;
}
catch (IOException e)
{
File.AppendAllTextAsync(hashList, $"An exception occurred:\nError code: " + $"{e.HResult & 0x0000FFFF}\nMessage: {e.Message}" + myFilename + "\n");
badcounter++;
}
finally
{
if (stream != null)
{
myFileMd5 = md5.ComputeHash(stream);
stream.Close();
}
}
return (myFileMd5);
}
Usually it is not a good practice to use the finally block to continue your processing logic. The finally block is executed in any case even if there is an exception catched or not. So your logic inside the finally block needs to be protected by the stream open failure and, not probable, but what if the same ComputeHash throws an exception?
So, I would move the logic inside the try block. If there is an exception the ComputeHash is not executed anyway and with the using statement you don't need to close the stream.
// This class will be used to comunicate back to the caller the result of the hash
// Try to avoid using too many global variables if possible. They make your code very
// unmaintenable.
public class ComputeStatus
{
public string errorText {get;set;} = "";
public byte[] hash {get;set;}
}
public ComputeStatus MyComputeHash(string filename)
{
ComputeStatus status = new ComputeStatus();
try
{
using var stream = new FileStream(myFilename, FileMode.Open);
status.hash = md5.ComputeHash(stream);
return status;
}
catch (FileNotFoundException)
{
string error = $"The file {myFilename} or directory cannot be found.";
// This can now be moved outside the method as well and done just one
// time by the caller in case of error text.
// File.AppendAllTextAsync(hashList, error);
status.errorText = error;
}
..... all the other catch blocks follow
return status;
}
Now the calling code just need to check if the ComputeStatus instance returned contains an error message or not. Let the error counting be handled at that level.
Something like this should work:
private void button1_Click(object sender, EventArgs e)
{
List<string> files = new List<string>();
files.Add(#"C:\file1.txt");
files.Add(#"C:\file2.txt");
files.Add(#"C:\file3.txt");
foreach(string myFilename in files)
{
//... your existing code...
}
}
I will be amazed if I find a solution for this, since it is very specific and vague, but I figured I would try. I'll try to give as much information as humanly possible, since I've been searching for answers for some time now.
I am building a utility in C# which copies records from a file in a library on the i-series/AS400 and builds an encrypted text file with each record from the AS400 as a comma separated string. In the file, it will have values like filename, fieldvalue1, fieldvalue2, fieldvalue3. I then take that text file to another PC, and run a C# utility which copies that record into the same file name in a library over there on a different i-series machine. Unfortunately, I receive the outside bounds of the array exception in some cases, but I cannot determine why. In the record just prior to the exception, the record looks pretty much the same and it works fine. My code is below in a nutshell. I usually don't give up, but I don't expect to ever figure this out. If someone does, I'll probably sing karaoke tonight.
// Select records from AS400 file and write them to text file
Recordset rs = new Recordset();
sqlQuery = "SELECT * FROM " + dataLibrary + "." + fileName;
try
{
rs.Open(sqlQuery, con);
while (!rs.EOF)
{
int[] fieldLengths;
fieldLengths = new int[rs.Fields.Count];
String[] fieldValues;
fieldValues = new String[rs.Fields.Count];
String fullString = "";
for (i = 0; i < rs.Fields.Count; i++)
{
fieldLengths[i] += rs.Fields[i].DefinedSize;
fieldValues[i] += rs.Fields[i].Value;
}
fullString = fileName + "," + String.Join(",", fieldValues);
fullString = Functions.EncryptString(fullString);
File.AppendAllText(savefile.FileName, fullString + Environment.NewLine);
rs.MoveNext();
}
}
catch (Exception ex)
{
}
cmd.Dispose();
// This gives me a text file of filename, fieldvalue1, fieldvalue2, etc...
// Next, I take the file to another system and run this process:
while ((myString = inputFile.ReadLine()) != null)
{
int stringLength = myString.Length;
String[] valuesArray = myString.Split(',');
for (i = 0; i < valuesArray.Length; i++)
{
if (i == 0)
{
fileName = valuesArray[0];
// Create file if it doesn't exist already
createPhysicalFile(newLibrary, fileName);
SQLStatement = "INSERT INTO " + newLibrary + "." + fileName + "VALUES(";
}
else
{
if (i == valuesArray.Length - 1)
{
SQLStatement += "#VAL" + i + ")";
}
else
{
SQLStatement += "#VAL" + i + ", ";
}
}
}
try
{
using (connection)
{
try
{
connection.Open();
}
catch (Exception ex)
{
}
// Create a new SQL command
iDB2Command command = new iDB2Command(SQLStatement, connection);
for (i = 1; i < valuesArray.Length; i++)
{
try
{
command.Parameters.AddWithValue("#VAL" + i, (valuesArray[i]));
}
catch (Exception ex)
{
}
}
// Just split the array into a string to visually check
// differences in the records
String arraySplit = ConvertStringArrayToString(valuesArray);
// The query gets executed here. The command looks something
// like:
// INSERT INTO LIBNAME.FILENAME VALUES(#VAL!, #VAL2, #VAL3, #VAL4)
// There are actually 320 fields in the file I'm having a problem with,
// so it's possible I'm overlooking something. I have narrowed it down to
// field # 316 when the exception occurs, but in both cases
// field 316 is blanks (when it works and when it doesn't).
command.ExecuteNonQuery();
}
}
catch (Exception ex)
{
// Here I get the exception out of bounds error in MSCORLIB.DLL.
// Some records are added fine, while others cause this exception.
// I cannot visibly tell any major differences, nor do I see any
// errors in the AS400 job log or anything in C# that would lead me
// down a certain path.
String error = ex.Message;
}
}
For what it's worth, I found this happening one a smaller file in the system and was able to figure out what going on, after painstaking research into the code and the net. Basically, the file file has numeric fields on the i-series. Somehow, the records were written to the file on the original system with null values in the numeric fields instead of numeric values. When storing the original records, I had to do this calculation:
String fieldType = rs.Fields[i].Type.ToString();
object objValue = rs.Fields[i].Value;
if (fieldType == "adNumeric" && objValue is DBNull)
{
fieldValues[i] += "0";
}
else
{
fieldValues[i] += rs.Fields[i].Value;
}
After this, if null values were found in one of the numeric fields, it just put "0" in it's place so that when writing to the new machine, it would put a valid numeric character in there and continue on writing the rest of the values. Thanks for all the advice and moral support. :)
I have the following code, just to test connection:
public void Test()
{
SqlCeConnection conn = new SqlCeConnection(#"Data Source=/Application/Database.sdf;");
try
{
conn.Open();
label1.text = "Connection!";
}
catch (Exception ee)
{
label1.text = "No connection!";
}
}
When trying to connect to this database, the application throws an exception at conn.Open() saying
SqlCeException was unhandled
and nothing more. The exception message is blank, so I'm having a hard time figuring out what went wrong.
The database file is there, and the application returns true with
File.Exist(#"/Application/Database.sdf");
so it does have access to the file.
I'm probably doing something really wrong here, can anyone help me out with this?
I'm using Compact Framework 2.0 on Windows CE 5, and the application in question is an existing one. I'm trying to add a database to it so I can load large amounts of data much more easier.
What Erik is saying is change your code to this:
public void Test()
{
SqlCeConnection conn = new SqlCeConnection(#"Data Source=/Application/Database.sdf;");
try
{
conn.Open();
label1.text = "Connection!";
}
catch (SqlCeException ee) // <- Notice the use of SqlCeException to read your errors
{
SqlCeErrorCollection errorCollection = ee.Errors;
StringBuilder bld = new StringBuilder();
Exception inner = ee.InnerException;
if (null != inner)
{
MessageBox.Show("Inner Exception: " + inner.ToString());
}
// Enumerate the errors to a message box.
foreach (SqlCeError err in errorCollection)
{
bld.Append("\n Error Code: " + err.HResult.ToString("X"));
bld.Append("\n Message : " + err.Message);
bld.Append("\n Minor Err.: " + err.NativeError);
bld.Append("\n Source : " + err.Source);
// Enumerate each numeric parameter for the error.
foreach (int numPar in err.NumericErrorParameters)
{
if (0 != numPar) bld.Append("\n Num. Par. : " + numPar);
}
// Enumerate each string parameter for the error.
foreach (string errPar in err.ErrorParameters)
{
if (String.Empty != errPar) bld.Append("\n Err. Par. : " + errPar);
}
}
label1.text = bld.ToString();
bld.Remove(0, bld.Length);
}
}
The generic Exception you are catching right now can not give you the details of the SqlCeException.
I'm new to C# (worked in PHP, Python, and Javascript) and I'm trying to more or less make a duplicate of another page and change some things - to make a form and database submission.
Anyway, here's the code:
public partial class commenter : System.Web.UI.Page
{
string employee_reviewed;
//public Commenter();
public void SaveBtn_Click(object sender, EventArgs e)
{
if (CommentTB.Text == "Please enter a comment.")
{
String csname = "Email Error";
Type cstype = this.GetType();
ClientScriptManager cs = Page.ClientScript;
if (!cs.IsStartupScriptRegistered(cstype, csname))
{
String cstext = "alert('Please submit at least one comment.');";
cs.RegisterStartupScript(cstype, csname, cstext, true);
}
FormMessage.Text = "Please submit at least one comment.";
return;
}
string comment = CommentTB.Text;
comment = comment.Replace("'", "''");
comment = comment.Replace("’", "''");
comment = comment.Replace("`", "''");
try
{
//myCommand.Connection.Open();
//myCommand.ExecuteNonQuery();
//myCommand.Connection.Close();
MySqlCommand myCommand;
MySqlConnection connection;
string connStringName = "server=localhost;database=hourtracking;uid=username;password=password";
connection = new MySqlConnection(connStringName);
string sql_query;
sql_query = "insert into peer_review_comment " + " (emp_id, comment)" + " values(?employeeid, ?comment) ";
//String csname = "Email Error";
//Type cstype = this.GetType();
//ClientScriptManager cs = Page.ClientScript;
//cs.RegisterStartupScript(cstype, csname, sql_query, true);
myCommand = new MySqlCommand(sql_query, connection);
//FormMessage.Text = sql_query;
//return;
Trace.Write("comment = ", comment);
myCommand.Parameters.Add(new MySqlParameter("?employeeid", ViewState["employeeid"].ToString()));
myCommand.Parameters.Add(new MySqlParameter("?comment", comment));
try
{
myCommand.Connection.Open();
myCommand.ExecuteNonQuery();
myCommand.Connection.Close();
}
catch (Exception ex)
{
FormMessage.Text = "Error:SaveBtn_Click - " + ex.Message;
}
//SendNotification(from, to, cc, subject, body, attach);
FormMessage.Text = "\n Thank you for leaving anonymous feedback for " + employee_reviewed; ;
ThankyouDiv.Visible = true;
FormFieldDiv.Visible = false;
reviewHeader.Visible = false;
}
catch (Exception ex)
{
FormMessage.Text = "Error:SaveBtn_Click - " + ex.Message;
}
}
}
I really have little idea what I'm doing - I'm reading the tutorials, but C# is a significantly different language than I am used to.
I get the Javascript alert when I do not change the text currently, but submission isn't working - I want it to submit to peer_review_comment database table, and fill in employeeid as well as the submitted comment.
Sorry if my understanding is so spotty, I am a TOTAL C# newbie (currently reading http://www.csharp-station.com/Tutorial/CSharp/)
My guess is the problem is here:
try
{
myCommand.Connection.Open();
myCommand.ExecuteNonQuery();
myCommand.Connection.Close();
}
catch (Exception ex)
{
FormMessage.Text = "Error:SaveBtn_Click - " + ex.Message;
// no "return;" !!
}
//SendNotification(from, to, cc, subject, body, attach);
FormMessage.Text = "\n Thank you for leaving anonymous feedback for " +
employee_reviewed; ;
Your catch block is setting the FormMessage.Text value bot not exiting the method, so the method keeps executing where the catch block finishes off, resetting the Text value and appearing that no exception was thrown.
add a return; at the end of your catch block to see the excpetion message.
Some general guidelines to make these kinds of problems easier to trap:
Don't try to do too much in one method. Have one method that validates the message (or do it client-side using Validators, another to do the DB call, etc.
Learn to use the debugger. You can step through code and get a better idea of what causes these kinds of errors.
Unless you can DO something about an exception, there's no harm in letting them bubble up to a higher level event handler (like Elmah) so exceptions don't get accidentally swallowed like it does here. In general it's preferrable to re-throw exceptions in lower-level methods (maybe adding some context or a user-friendly message) so the higher level exception handling can decide what to do (show a message, log, etc.)
I have taken the liberty of refactoring your code. This shows some better code practices but may also show you the problem. Along with these code changes I would also recommend reading D. Stanley's answer; there are some helpful tips in there as well.
if (CommentTB.Text == "Please enter a comment.")
{
String csname = "Email Error";
Type cstype = this.GetType();
ClientScriptManager cs = Page.ClientScript;
if (!cs.IsStartupScriptRegistered(cstype, csname))
{
String cstext = "alert('Please submit at least one comment.');";
cs.RegisterStartupScript(cstype, csname, cstext, true);
}
FormMessage.Text = "Please submit at least one comment.";
return;
}
// This helps some but very little, just wanted to show an alternative to writing three statements
string comment = CommentTB.Text.Replace("'", "''").Replace("’", "''").Replace("`", "''");
//string comment = CommentTB.Text;
//comment = comment.Replace("'", "''");
//comment = comment.Replace("’", "''");
//comment = comment.Replace("`", "''");
try
{
// No need to do string concatenation...just make it one string.
// sql_query = "insert into peer_review_comment " + " (emp_id, comment)" + " values(?employeeid, ?comment) ";
string sql_query = "insert into peer_review_comment (emp_id, comment) values (?employeeid, ?comment) ";
string connStringName = "server=localhost;database=hourtracking;uid=username;password=password";
// Use a "using" clause because it guarantees the connection is closed even when an exception occurs.
using (MySqlConnection connection = new MySqlConnection(connStringName))
{
connection.Open();
// Again, use a "using" clause
using (MySqlCommand myCommand = new MySqlCommand(sql_query, connection))
{
Trace.Write("comment = ", comment);
myCommand.Parameters.Add(new MySqlParameter("?employeeid", ViewState["employeeid"].ToString()));
myCommand.Parameters.Add(new MySqlParameter("?comment", comment));
myCommand.ExecuteNonQuery();
// No need for a Close statement with "using" clause.
//myCommand.Connection.Close();
}
}
FormMessage.Text = "\n Thank you for leaving anonymous feedback for " + employee_reviewed;
ThankyouDiv.Visible = true;
FormFieldDiv.Visible = false;
reviewHeader.Visible = false;
}
catch (Exception ex)
{
FormMessage.Text = "Error:SaveBtn_Click - " + ex.Message;
}
I am having some problems with a piece of code, I am trying to import data from a source (at this time an access database) into a custom form but i keep getting the above error.
When i use a VBscript inside the source database all contacts import correctly.
When i repair the PST it still gives this error.
When i add a delay of 450 ms. the error also occurs but later on in the process.
Having Outlook opened or closed does not matter.
I am using the following method
string[] arrFolders = strFolders.Split('\\');
Outlook.Application app = null;
Outlook.MAPIFolder folder = null;
try {
app = new Outlook.Application();
folder = app.GetNamespace("MAPI").Folders[arrFolders[0]];
} catch (Exception ex) {
writeLogLine("Error creating Outlook instance: " + ex.Message);
MessageBox.Show("Error creating Outlook instance\r\n" + ex.Message);
intErrorCount++;
blnHasErrors = true;
blnAbort = true;
}
try {
for (int i = 1; i < arrFolders.Length; i++) {
folder = folder.Folders[arrFolders[i]];
}
} catch (Exception ex) {
writeLogLine("Error navigating to DRM folder: " + ex.Message);
MessageBox.Show("Error navigating to DRM folder\r\n" + ex.Message);
intErrorCount++;
blnHasErrors = true;
blnAbort = true;
}
setProgressbarMaximum(dtResults.Rows.Count);
setProgressbarMode(ProgressBarStyle.Continuous);
//int intRowCount = 0;
foreach (DataRow drItem in dtResults.Rows) {
if (strDRMType == "Contact") {
try {
Outlook.ContactItem x = (Outlook.ContactItem)folder.Items.Add("IPM.Contact." + strFormName);
for (int i = 0; i < arrMappings.GetLength(0); i++) {
if (arrMappings[i, 1] != null && drItem[arrMappings[i, 0]].ToString() != "") {
x.UserProperties[arrMappings[i, 1]].Value = drItem[arrMappings[i, 0]].ToString();
}
}
x.Save();
} catch (Exception ex) {
writeLogLine("Error importing contact: " + ex.Message);
intErrorCount++;
blnHasErrors = true;
}
}
as i said, when i loop the code it will throw exceptions after 100 to 200 contacts, when i add a delay it will get to contact 400/500 before failing.
This code is supposed to be for a generic import tool for this specific form so there is no need for hardcoding the source column names to the form fields in the import code.
Any help is appreciated.
I'm assuming this is not an Outlook add-in, since you say it doesn't matter if OL is open or closed, right?
One thing you may want to do is ensure you are releasing the COM objects once you are done with them, using System.Runtime.InteropServices.Marshal.ReleaseComObject(...). Also, when you use dot notation like "namespace.Folders[..].Name" you are actually leaking a reference to both the Folders collection object and a Folder object.
When you do folders.Items.Add(...) inside a loop, that leaks a lot of objects.
So, clean up your COM references first, and see how that affects your situation.
Here's how I typically use COM objects:
MyComLib.Foo foo = null;
try
{
foo = new MyComLib.Foo();
foo.DoSomething();
} catch(COMException exc)
{
// handle error, or rethrow
}
finally
{
if(foo != null)
Marshal.ReleaseComObject(foo);
}