
Question:
I'm using the CustomSettingProvider as can be found here : <a href="http://www.codeproject.com/KB/vb/CustomSettingsProvider.aspx" rel="nofollow">http://www.codeproject.com/KB/vb/CustomSettingsProvider.aspx</a>
On some machines, a null reference exception is thrown :
System.NullReferenceException: .
bij cx.a(SettingsPropertyValue A_0)
bij cx.a(SettingsContext A_0, SettingsPropertyValueCollection A_1)
bij System.Configuration.SettingsBase.SaveCore()
bij System.Configuration.SettingsBase.Save()
bij System.Configuration.ApplicationSettingsBase.Save()
cx.a() is either the getvalue or setvalue method ..
Any ideas ?
........... EDIT ...............................
<strong>This GetValue method returns a XPathException: Expression must evaluate to a node-set when executing (SelectSingleNode method)</strong>
private string GetValue(SettingsProperty setting)
{
string ret = "";
if (setting == null)
return "";
try
{
//Try to read setting ??
XmlNode foundNode = null;
string nodeSelectStr = SETTINGSROOT + "/" + SystemInformation.ComputerName + "/" + setting.Name;
if (IsRoaming(setting))
{
nodeSelectStr = SETTINGSROOT + "/" + setting.Name;
}
foundNode = SettingsXML.SelectSingleNode(nodeSelectStr);
if (foundNode != null)
{
ret = foundNode.InnerText;
}
else //Not found .. ?
{
if ((setting.DefaultValue != null))
{
ret = setting.DefaultValue.ToString();
}
else
{
ret = "";
}
}
}
catch (Exception exc)
{
Errors.CatchError("ErrorHintObjectOrAction", exc);
}
return ret;
}
public class CustomSettingProvider : SettingsProvider
{
//XML Root Node
const string SETTINGSROOT = "Settings";
public override void Initialize(string name, NameValueCollection col)
{
base.Initialize(this.ApplicationName, col);
}
public override string ApplicationName
{
get
{
if (Application.ProductName.Trim().Length > 0)
{
return Application.ProductName;
}
else
{
FileInfo fi = new FileInfo(Application.ExecutablePath);
return fi.Name.Substring(0, fi.Name.Length - fi.Extension.Length);
}
}
//Do nothing
set { }
}
public virtual string GetAppSettingsPath()
{
return ApplicatiePaths.SettingsPath;
//Used to determine where to store the settings
//System.IO.FileInfo fi = new System.IO.FileInfo(Application.ExecutablePath);
//return fi.DirectoryName;
}
public virtual string GetAppSettingsFilename()
{
//Used to determine the filename to store the settings
return ApplicationName + ".settings";
}
public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection propvals)
{
//Iterate through the settings to be stored
//Only dirty settings are included in propvals, and only ones relevant to this provider
foreach (SettingsPropertyValue propval in propvals)
{
SetValue(propval);
}
try
{
SettingsXML.Save(Path.Combine(GetAppSettingsPath(), GetAppSettingsFilename()));
}
catch (Exception ex)
{
//Ignore if cant save, device been ejected
}
}
public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection props)
{
//Create new collection of values
SettingsPropertyValueCollection values = new SettingsPropertyValueCollection();
//Iterate through the settings to be retrieved
foreach (SettingsProperty setting in props)
{
SettingsPropertyValue value = new SettingsPropertyValue(setting);
value.IsDirty = false;
value.SerializedValue = GetValue(setting);
values.Add(value);
}
return values;
}
private XmlDocument m_SettingsXML = null;
private XmlDocument SettingsXML
{
get
{
//If we dont hold an xml document, try opening one.
//If it doesnt exist then create a new one ready.
if (m_SettingsXML == null)
{
m_SettingsXML = new XmlDocument();
try
{
m_SettingsXML.Load(Path.Combine(GetAppSettingsPath(), GetAppSettingsFilename()));
}
catch (Exception ex)
{
//Create new document
XmlDeclaration dec = m_SettingsXML.CreateXmlDeclaration("1.0", "utf-8", string.Empty);
m_SettingsXML.AppendChild(dec);
XmlNode nodeRoot = null;
nodeRoot = m_SettingsXML.CreateNode(XmlNodeType.Element, SETTINGSROOT, "");
m_SettingsXML.AppendChild(nodeRoot);
}
}
return m_SettingsXML;
}
}
private string GetValue(SettingsProperty setting)
{
string ret = "";
//This method is throwing the null reference exception,
//so 'setting' has got to be null ??
try
{
if (IsRoaming(setting))
{
ret = SettingsXML.SelectSingleNode(SETTINGSROOT + "/" + setting.Name).InnerText;
}
else
{
ret = SettingsXML.SelectSingleNode(SETTINGSROOT + "/" + SystemInformation.ComputerName + "/" + setting.Name).InnerText;
}
}
catch (Exception ex)
{
if ((setting.DefaultValue != null))
{
ret = setting.DefaultValue.ToString();
}
else
{
ret = "";
}
}
return ret;
}
private void SetValue(SettingsPropertyValue propVal)
{
XmlElement MachineNode = default(XmlElement);
XmlElement SettingNode = default(XmlElement);
//Determine if the setting is roaming.
//If roaming then the value is stored as an element under the root
//Otherwise it is stored under a machine name node
try
{
if (IsRoaming(propVal.Property))
{
SettingNode = (XmlElement)SettingsXML.SelectSingleNode(SETTINGSROOT + "/" + propVal.Name);
}
else
{
SettingNode = (XmlElement)SettingsXML.SelectSingleNode(SETTINGSROOT + "/" + SystemInformation.ComputerName + "/" + propVal.Name);
}
}
catch (Exception ex)
{
SettingNode = null;
}
//Check to see if the node exists, if so then set its new value
if ((SettingNode != null))
{
SettingNode.InnerText = propVal.SerializedValue.ToString();
}
else
{
if (IsRoaming(propVal.Property))
{
//Store the value as an element of the Settings Root Node
SettingNode = SettingsXML.CreateElement(propVal.Name);
SettingNode.InnerText = propVal.SerializedValue.ToString();
SettingsXML.SelectSingleNode(SETTINGSROOT).AppendChild(SettingNode);
}
else
{
//Its machine specific, store as an element of the machine name node,
//creating a new machine name node if one doesnt exist.
try
{
MachineNode = (XmlElement)SettingsXML.SelectSingleNode(SETTINGSROOT + "/" + SystemInformation.ComputerName);
}
catch (Exception ex)
{
MachineNode = SettingsXML.CreateElement(SystemInformation.ComputerName);
SettingsXML.SelectSingleNode(SETTINGSROOT).AppendChild(MachineNode);
}
if (MachineNode == null)
{
MachineNode = SettingsXML.CreateElement(SystemInformation.ComputerName);
SettingsXML.SelectSingleNode(SETTINGSROOT).AppendChild(MachineNode);
}
SettingNode = SettingsXML.CreateElement(propVal.Name);
SettingNode.InnerText = propVal.SerializedValue.ToString();
MachineNode.AppendChild(SettingNode);
}
}
}
private bool IsRoaming(SettingsProperty prop)
{
//Determine if the setting is marked as Roaming
foreach (DictionaryEntry d in prop.Attributes)
{
Attribute a = (Attribute)d.Value;
if (a is System.Configuration.SettingsManageabilityAttribute)
{
return true;
}
}
return false;
}
}
Answer1:I noticed that you have several catch (Exception ex)
This is going to make it difficult because your swallowing the likely cause of the problem.
You should probably remove them and then see what the exception that gets thrown. Only catch exceptions if there's an exception you can actually do something about (converting a null value to a default). And even then it should be a <em>specific</em> exception not System.Exception
Answer2:The cause of the problems :
some machine names start with numbers. ie. "965GDF5". XML Tags cannot start with numbers though, hence all the errors.