private new void WriteValues(string p_SubKeyName, ref Generic.SortedList <string, string> p_KeyValuePairs, bool p_CheckForCurrentProfileStore) { // Write all key values to an XML file // SubKey has to be absolute from the profile store root XmlWriterSettings WriterSettings; string FName; int Ct; swSupport.Reset(); swSupport.Start(); // Start timing this call TL.LogMessage(" WriteValues", " SubKeyName: " + p_SubKeyName); if (Strings.Left(p_SubKeyName, 1) != @"\") { p_SubKeyName = @"\" + p_SubKeyName; } try { Ct = 0; foreach (Generic.KeyValuePair <string, string> kvp in p_KeyValuePairs) { Ct += 1; TL.LogMessage(" WriteValues List", " " + Ct.ToString() + " " + kvp.Key + " = " + kvp.Value); } WriterSettings = new XmlWriterSettings(); WriterSettings.Indent = true; FName = FileStore.FullPath(p_SubKeyName + @"\" + VALUES_FILENAME_NEW); XmlWriter Writer; FileStream FStream; FStream = new FileStream(FName, FileMode.Create, FileAccess.Write, FileShare.None, 2048, FileOptions.WriteThrough); Writer = XmlWriter.Create(FStream, WriterSettings); // Writer = XmlWriter.Create(FName, WriterSettings) using (Writer) { Writer.WriteStartDocument(); Writer.WriteStartElement(PROFILE_NAME); // Write the profile element Writer.WriteStartElement(DEFAULT_ELEMENT_NAME); // Write the default element Writer.WriteAttributeString(VALUE_ATTRIBUTE_NAME, p_KeyValuePairs.Item(COLLECTION_DEFAULT_VALUE_NAME)); // Write the default value Writer.WriteEndElement(); Ct = 0; foreach (Generic.KeyValuePair <string, string> kvp in p_KeyValuePairs) // Write each named value in turn { Ct += 1; TL.LogMessage(" Writing Value", " " + Ct.ToString() + " " + kvp.Key + " = " + kvp.Value); if (kvp.Value == null) { TL.LogMessage(" Writing Value", " WARNING - Suppplied Value is Nothing not empty string"); } switch (kvp.Key) { case object _ when COLLECTION_DEFAULT_VALUE_NAME // Ignore the default value entry : { break; } default: { Writer.WriteStartElement(VALUE_ELEMENT_NAME); // Write the element name Writer.WriteAttributeString(NAME_ATTRIBUTE_NAME, kvp.Key); // Write the name attribute Writer.WriteAttributeString(VALUE_ATTRIBUTE_NAME, kvp.Value); // Write the value attribute Writer.WriteEndElement(); // Close this element break; } } } Writer.WriteEndElement(); // Flush and close the writer object to complete writing of the XML file. Writer.Close(); // Actualy write the XML to a file } try { FStream.Flush(); FStream.Close(); FStream.Dispose(); FStream = null; } catch (Exception ex) { }// Ensure no error occur from this tidying up Writer = null; try // New file successfully created so now rename the current file to original and rename the new file to current { if (p_CheckForCurrentProfileStore) { FileStore.Rename(p_SubKeyName + @"\" + VALUES_FILENAME, p_SubKeyName + @"\" + VALUES_FILENAME_ORIGINAL); } try { FileStore.Rename(p_SubKeyName + @"\" + VALUES_FILENAME_NEW, p_SubKeyName + @"\" + VALUES_FILENAME); } catch (Exception ex2) { // Attempt to rename new file as current failed so try and restore the original file TL.Enabled = true; TL.LogMessage("XMLAccess:WriteValues", "Unable to rename new profile file to current - " + p_SubKeyName + @"\" + VALUES_FILENAME_NEW + "to " + p_SubKeyName + @"\" + VALUES_FILENAME + " " + ex2.ToString()); try { FileStore.Rename(p_SubKeyName + @"\" + VALUES_FILENAME_ORIGINAL, p_SubKeyName + @"\" + VALUES_FILENAME); } catch (Exception ex3) { // Restoration also failed so no clear recovery from this point TL.Enabled = true; TL.LogMessage("XMLAccess:WriteValues", "Unable to rename original profile file to current - " + p_SubKeyName + @"\" + VALUES_FILENAME_ORIGINAL + "to " + p_SubKeyName + @"\" + VALUES_FILENAME + " " + ex3.ToString()); } } } catch (Exception ex1) { // No clear remedial action as the current file rename failed so just leave as is TL.Enabled = true; TL.LogMessage("XMLAccess:WriteValues", "Unable to rename current profile file to original - " + p_SubKeyName + @"\" + VALUES_FILENAME + "to " + p_SubKeyName + @"\" + VALUES_FILENAME_ORIGINAL + " " + ex1.ToString()); } WriterSettings = null; swSupport.Stop(); TL.LogMessage(" WriteValues", " Created cache entry " + p_SubKeyName + " - " + swSupport.ElapsedMilliseconds + " milliseconds"); } catch (Exception ex) { TL.LogMessageCrLf(" WriteValues", " Exception " + p_SubKeyName + " " + ex.ToString()); Interaction.MsgBox("XMLAccess:Writevalues " + p_SubKeyName + " " + ex.ToString()); } }
private Generic.SortedList <string, string> ReadValues(string p_SubKeyName) { Generic.SortedList <string, string> Retval = new Generic.SortedList <string, string>(); // Read all values in a key - SubKey has to be absolute from the profile store root XmlReaderSettings ReaderSettings; string LastElementName = ""; string NextName = ""; string ValueName = ""; bool ReadOK = false; int RetryCount; bool ErrorOccurred = false; string ValuesFileName; // Name of the profile file from which to read bool ExistsValues, ExistsValuesOriginal, ExistsValuesNew; swSupport.Reset(); swSupport.Start(); // Start timing this call if (Strings.Left(p_SubKeyName, 1) != @"\") { p_SubKeyName = @"\" + p_SubKeyName; // Condition to have leading \ } TL.LogMessage(" ReadValues", " SubKeyName: " + p_SubKeyName); ValuesFileName = VALUES_FILENAME; // Initialise to the file holding current values RetryCount = -1; // Initialise to ensure we get RETRY_Max number of retrys // Determine what files exist and handle the case where this key has not yet been created ExistsValues = FileStore.Exists(p_SubKeyName + @"\" + VALUES_FILENAME); ExistsValuesOriginal = FileStore.Exists(p_SubKeyName + @"\" + VALUES_FILENAME_ORIGINAL); ExistsValuesNew = FileStore.Exists(p_SubKeyName + @"\" + VALUES_FILENAME_NEW); if (!ExistsValues & !ExistsValuesOriginal) { throw new ProfileNotFoundException("No profile files exist for this key: " + p_SubKeyName); } do { RetryCount += 1; try { ReaderSettings = new XmlReaderSettings(); ReaderSettings.IgnoreWhitespace = true; using (XmlReader Reader = XmlReader.Create(FileStore.FullPath(p_SubKeyName + @"\" + ValuesFileName), ReaderSettings)) { Reader.Read(); Reader.Read(); // Start reading profile strings while (Reader.Read()) { switch (Reader.NodeType) { case XmlNodeType.Element: { switch (Reader.Name) { case object _ when DEFAULT_ELEMENT_NAME: { Retval.Add(COLLECTION_DEFAULT_VALUE_NAME, Reader.GetAttribute(VALUE_ATTRIBUTE_NAME)); TL.LogMessage(" ReadValues", " found " + COLLECTION_DEFAULT_VALUE_NAME + " = " + Retval.Item(COLLECTION_DEFAULT_VALUE_NAME)); break; } case object _ when VALUE_ELEMENT_NAME: { ValueName = Reader.GetAttribute(NAME_ATTRIBUTE_NAME); Retval.Add(ValueName, Reader.GetAttribute(VALUE_ATTRIBUTE_NAME)); TL.LogMessage(" ReadValues", " found " + ValueName + " = " + Retval.Item(ValueName)); break; } default: { TL.LogMessage(" ReadValues", " ## Found unexpected Reader.Name: " + Reader.Name.ToString()); break; } } break; } default: { break; } } } Reader.Close(); } swSupport.Stop(); TL.LogMessage(" ReadValues", " added to cache - " + swSupport.ElapsedMilliseconds + " milliseconds"); ReadOK = true; } catch (Exception ex) { ErrorOccurred = true; if (RetryCount == RETRY_MAX) { if (ValuesFileName == VALUES_FILENAME) { ValuesFileName = VALUES_FILENAME_ORIGINAL; RetryCount = -1; LogEvent("XMLAccess:ReadValues", "Error reading profile on final retry - attempting recovery from previous version", EventLogEntryType.Warning, EventLogErrors.XMLAccessRecoveryPreviousVersion, ex.ToString()); TL.LogMessageCrLf(" ReadValues", "Final retry exception - attempting recovery from previous version: " + ex.ToString()); } else { LogEvent("XMLAccess:ReadValues", "Error reading profile on final retry", EventLogEntryType.Error, EventLogErrors.XMLAccessReadError, ex.ToString()); TL.LogMessageCrLf(" ReadValues", "Final retry exception: " + ex.ToString()); throw new ProfilePersistenceException("XMLAccess Exception", ex); } } else { LogEvent("XMLAccess:ReadValues", "Error reading profile - retry: " + RetryCount, EventLogEntryType.Warning, EventLogErrors.XMLAccessRecoveryPreviousVersion, ex.Message); TL.LogMessageCrLf(" ReadValues", "Retry " + RetryCount + " exception: " + ex.ToString()); } } if (ErrorOccurred) { System.Threading.Thread.Sleep(RETRY_INTERVAL); } }while (!ReadOK)// Get rid of the XML version string// Read in the Profile name tag// Found default value// Fount an element name// Close the IO readers// Set the exit flag here when a read has been successful // Wait if an error occurred ; if (ErrorOccurred) { LogEvent("XMLAccess:ReadValues", "Recovered from read error OK", EventLogEntryType.SuccessAudit, EventLogErrors.XMLAccessRecoveredOK, null /* TODO Change to default(_) if this is not a reference type */); TL.LogMessage(" ReadValues", "Recovered from read error OK"); } return(Retval); }