I have bountified a question that kind of morphed into this question; IOW, this is a more concise and understandable statement of the precise problem, but is very similar to Update 8 there.
Basically, mnuSendINV_Click() calls SendInventoryData(), which calls getDataAsXMLFromTable(), which throws the NRE.
More specifically, here is the code in context:
private void mnuSendINV_Click(object sender, EventArgs e)
{
SendInventoryData();
}
private void SendInventoryData()
{
String siteNum = String.Empty;
ArrayList sbInventories = new ArrayList();
foreach (String tbl in listboxWork.Items)
{
// Ignore CCR tables; just get INV tables
if (tbl.IndexOf("CCR") >-1) continue;
String tblName = getTableNameForInventoryName(tbl);
siteNum = getSiteNumberFromInventoryName(tbl);
sbInventories.Add(tblName);
}
foreach (string tbl in sbInventories)
{
string strData = getDataAsXMLFromTable(tbl, "003");
. . .
}
}
private String getDataAsXMLFromTable(String tableName, String siteNum)
{
string xmlOutput = String.Empty;
// data/xml fields
String lineId;
String refNum;
. . .
String newItem;
String paddedSiteNum = Prepad(3, siteNum);
string connStr = String.Format("Data Source=\"\\My Documents\\HHSDB{0}.SDF\"", paddedSiteNum);
String qry = String.Format("SELECT * FROM {0}", tableName);
MessageBox.Show(String.Format("connstr is {0}; qry is {1}", connStr, qry));
SqlCeConnection sqlceConn;
SqlCeCommand sqlceCmd;
try
{
sqlceConn = new SqlCeConnection(connStr);
sqlceCmd = new SqlCeCommand(qry, sqlceConn);
sqlceCmd.CommandType = CommandType.Text;
MessageBox.Show("Made it just before conn.Open()"); // <= I see this
if ((null != sqlceConn) && (!sqlceConn.State.Equals(ConnectionState.Open)))
{
MessageBox.Show("Will try to Open"); // <= I see this
sqlceConn.Open(); // <= This is where the world explodes
}
MessageBox.Show("Made it just after conn.Open()"); // <= I don't see this/make it to here; I see the NRE instead
SqlCeDataReader dtr = sqlceCmd.ExecuteReader(CommandBehavior.Default);
XmlDocument doc = new XmlDocument();
XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", null, null);
doc.AppendChild(dec);// Create the root element
XmlElement root = doc.CreateElement("Command");
doc.AppendChild(root);
try
{
while (dtr.Read())
{
// outer INV
XmlElement invRec = doc.CreateElement("INV");
// Line ID
lineId = dtr["line_id"].ToString();
XmlElement _lineId = doc.CreateElement("line_id");
_lineId.InnerText = lineId;
invRec.AppendChild(_lineId);
// Ref Num
refNum = dtr["ref_no"].ToString();
XmlElement _refNum = doc.CreateElement("ref_no");
_refNum.InnerText = refNum;
invRec.AppendChild(_refNum);
. . .
// New Item
newItem = dtr["new_item"].ToString();
XmlElement _new_item = doc.CreateElement("new_item");
_new_item.InnerText = newItem;
invRec.AppendChild(_new_item);
root.AppendChild(invRec);
}
}
finally
{
xmlOutput = doc.OuterXml;
dtr.Close();
if (sqlceCmd.Connection.State == ConnectionState.Open)
{
sqlceCmd.Connection.Close();
}
}
}
catch (Exception ex)
{
MessageBox.Show(String.Format("inner ex is {0}", ex.InnerException.ToString()));
SSCS.ExceptionHandler(ex, "frmCentral.getDataAsXMLFromTable()");
}
return xmlOutput;
} //getDataAsXMLFromTable
Note: With this code, I see:
0) "connstr is Data Source="\My Documents\HHSDB003.SDF"; qry is SELECT * FROM INV12262006091415"
1) "Made it just before conn.open"
2) "Will try to open"
3) "Exception: Null Reference Exception"
INV12262006091415 does exist in HHSDB003.SDF
UPDATE
In response to Alexei's suspicion, here is the file in question on the device:
The .exe is in \Program Files\HHS
UPDATE 2
For clever neologism (seems to be no "StackTrace" available on the exception class):
UPDATE 3
StackTrace unavailable; compile fails with "'System.Exception' does not contain a definition for 'StackTrace'" and reds up:
UPDATE 4
I tried daniele3004's suggestion, with this basic code:
private void menuItemTestSendingXML_Click(object sender, System.EventArgs e)
{
// If one of the below works, try it with the String.Format() jazz
//string connStr = "Data Source=\"\\My Documents\\HHSDB003.SDF"; <= NRE, without a catch block
string connStr = @"Data Source= \\My Documents\\HHSDB003.SDF"; // NRE with a catch block IF InnerException not first checked for null
//string connStr = @"Data Source= \\My Documents\HHSDB003.SDF";
//string connStr = "Data Source= \\My Documents\\HHSDB003.SDF";
//string connStr = "Data Source= \\\My Documents\\HHSDB003.SDF";
SqlCeConnection conn = null;
try
{
try
{
conn = new SqlCeConnection(connStr);
conn.Open();
MessageBox.Show("it must have opened okay");
}
finally
{
conn.Close();
}
}
catch (Exception ex)
{
if (null == ex.InnerException)
{
MessageBox.Show("inner Ex is null");
}
MessageBox.Show(String.Format("msg is {0}", ex.Message));
}
}
What I see so far (I still have to test the other connStr options) is:
"InnerEx is null"
"msg is " // [ex.Message is blank]
If there is an exception (and there is, because I reach the catch block), why is InnerException null?
UPDATE 5
None of my attempts work (note the comments):
//string connStr = "Data Source=\"\\My Documents\\HHSDB003.SDF"; <= NRE
//string connStr = @"Data Source= \\My Documents\\HHSDB003.SDF"; // No NRE, but exception
//string connStr = @"Data Source= \\My Documents\HHSDB003.SDF"; // "inner ex is null; msg is [blank]
//string connStr = "Data Source= \\My Documents\\HHSDB003.SDF"; // ""
//string connStr = "Data Source= \\\My Documents\\HHSDB003.SDF"; <= won't even compile ("unrecognized escape sequence")
//string connStr = @"Data Source= My Documents\HHSDB003.SDF"; // "inner ex is null; msg is [blank]
//string connStr = "Data Source= My Documents\HHSDB003.SDF"; <= won't even compile ("unrecognized escape sequence")
string connStr = "Data Source= My Documents\\HHSDB003.SDF"; // "inner ex is null; msg is [blank]
I'm assuming there's something wrong with my connStr, but how else is it to be done?
UPDATE 6
Okay, I found this code by jp2code here:
SqlCeConnection conn = new SqlCeConnection(@"Data Source=/My Documents/HHSDB003.sdf;");
try
{
conn.Open();
MessageBox.Show("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);
}
}
MessageBox.Show(bld.ToString());
bld.Remove(0, bld.Length);
}
...and see that my backwhacks should be regular whacks.
If that would have fixed it, I would have waxed poetic about my whacks pathetic, but I still get an err:
I run this code immediately on starting the app, so I wouldn't expect it to be used elsewhere already, but I guess the real question is, how can I prevent it/work around it?
UPDATE 7
The slanting of the whacks apparently have nothing to do with it; I changed the connection string from forward whacks to the original back whacks and get the same exact err dialog.
UPDATE 8
Another oddity is, though, that if I use backwhacks instead of forward whacks in the Connection String, it actually does change the err msg a little:
(with backwhacks, the "Err. Par." path to the database does not appear in the err msg). As the examples I see show a backwhack, I'll assume that is the canonical/right way to do it, though...
UPDATE 9
When I, based on what I read here, added "File Mode=Read Write;" to my connection string so that it is:
@"Data Source=\My Documents\HHSDB003.sdf; File Mode=Read Write;");
...it gets worse in the sense that now it won't even show me the "80004005 There is a file sharing violation. A different process might be using the file." err msg any more. It instead gets cryptic and teases: