Encode & Decode string in WPF C# - c#

I am trying to encode & decode strings that are saved to an .ini settings file for a WPF app.
encoding & decoding class
class EncryptDecrypt
{
public static string Base64Encode(string plainText)
{
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
return System.Convert.ToBase64String(plainTextBytes);
}
public static string Base64Decode(string base64EncodedData)
{
var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
}
}
The encoding seems to be saved to the .ini file correctly, but decoding the entry from the .ini file seems to output incorrect string as per below;
encoding from password field works fine (on save_click)
inif.Write("APISettings", "HashKey", EncryptDecrypt.Base64Encode(hash_key.Password.ToString()));
but, reload app then navigating to same field/form the decode is not outputting entry correctly (as it is used to check http status of page)..
hash_key.Password = EncryptDecrypt.Base64Decode(inif.Read("APISettings", "HashKey"));
I can see that is outputting the string as weird wingdings characters.
UPDATE
Resolved by instead of saving to .ini file I saved to xml document, see below;
private void Save_Click(object sender, RoutedEventArgs e)
{
//Settings Data
string appfolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string ApplicationPath = System.IO.Path.Combine(appfolder, "MyApp/Application");
if (!Directory.Exists(ApplicationPath)) Directory.CreateDirectory(ApplicationPath);
//Encryption
if (!System.IO.File.Exists(ApplicationPath + #"\credentials.xml"))
{
XmlDocument doc = new XmlDocument();
//(1) the xml declaration is recommended, but not mandatory
XmlDeclaration xmlDeclaration = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
XmlElement root = doc.DocumentElement;
doc.InsertBefore(xmlDeclaration, root);
//(2) string.Empty makes cleaner code
XmlElement elementNode = doc.CreateElement(string.Empty, "Credentials", string.Empty);
doc.AppendChild(elementNode);
//Base URL
XmlElement elementNodeBaseUrl = doc.CreateElement(string.Empty, "BaseUrl", string.Empty);
elementNode.AppendChild(elementNodeBaseUrl);
elementNodeBaseUrl.InnerText = base_url.Text.ToString();
XmlElement elementNodeAdminPath = doc.CreateElement(string.Empty, "AdminPath", string.Empty);
elementNode.AppendChild(elementNodeAdminPath);
elementNodeAdminPath.InnerText = EncryptDecrypt.Base64Encode(admin_path.Password.ToString());
XmlElement elementNodeAdminName = doc.CreateElement(string.Empty, "AdminName", string.Empty);
elementNode.AppendChild(elementNodeAdminName);
elementNodeAdminName.InnerText = EncryptDecrypt.Base64Encode(admin_name.Password.ToString());
XmlElement elementNodeAdminPassword = doc.CreateElement(string.Empty, "AdminPassword", string.Empty);
elementNode.AppendChild(elementNodeAdminPassword);
elementNodeAdminPassword.InnerText = EncryptDecrypt.Base64Encode(admin_password.Password.ToString());
XmlElement elementNodeHashKey = doc.CreateElement(string.Empty, "HashKey", string.Empty);
elementNode.AppendChild(elementNodeHashKey);
elementNodeHashKey.InnerText = EncryptDecrypt.Base64Encode(hash_key.Password.ToString());
XmlElement elementNodeUpdated = doc.CreateElement(string.Empty, "Updated", string.Empty);
elementNode.AppendChild(elementNodeUpdated);
elementNodeUpdated.InnerText = DateTime.Now.ToString();
doc.Save(ApplicationPath + #"\credentials.xml");
}else{
XmlDocument doc = new XmlDocument();
//(1) the xml declaration is recommended, but not mandatory
XmlDeclaration xmlDeclaration = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
XmlElement root = doc.DocumentElement;
doc.InsertBefore(xmlDeclaration, root);
//(2) string.Empty makes cleaner code
XmlElement elementNode = doc.CreateElement(string.Empty, "Credentials", string.Empty);
doc.AppendChild(elementNode);
//Base URL
XmlElement elementNodeBaseUrl = doc.CreateElement(string.Empty, "BaseUrl", string.Empty);
elementNode.AppendChild(elementNodeBaseUrl);
elementNodeBaseUrl.InnerText = base_url.Text.ToString();
XmlElement elementNodeAdminPath = doc.CreateElement(string.Empty, "AdminPath", string.Empty);
elementNode.AppendChild(elementNodeAdminPath);
elementNodeAdminPath.InnerText = EncryptDecrypt.Base64Encode(admin_path.Password.ToString());
XmlElement elementNodeAdminName = doc.CreateElement(string.Empty, "AdminName", string.Empty);
elementNode.AppendChild(elementNodeAdminName);
elementNodeAdminName.InnerText = EncryptDecrypt.Base64Encode(admin_name.Password.ToString());
XmlElement elementNodeAdminPassword = doc.CreateElement(string.Empty, "AdminPassword", string.Empty);
elementNode.AppendChild(elementNodeAdminPassword);
elementNodeAdminPassword.InnerText = EncryptDecrypt.Base64Encode(admin_password.Password.ToString());
XmlElement elementNodeHashKey = doc.CreateElement(string.Empty, "HashKey", string.Empty);
elementNode.AppendChild(elementNodeHashKey);
elementNodeHashKey.InnerText = EncryptDecrypt.Base64Encode(hash_key.Password.ToString());
XmlElement elementNodeUpdated = doc.CreateElement(string.Empty, "Updated", string.Empty);
elementNode.AppendChild(elementNodeUpdated);
elementNodeUpdated.InnerText = DateTime.Now.ToString();
doc.Save(ApplicationPath + #"\credentials.xml");
}
Thread.Sleep(1000);
SaveButton.Visibility = Visibility.Hidden;
onclick_progress.Visibility = Visibility.Visible;
showProgress();
}

Related

Cannot change XmlDocument value?

I have a simple function which will simply change and read the value.
void ParseXml(string XmlFile)
{
string totalval = "";
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(new StringReader(XmlFile));
string xmlPathPattern = "//name";
XmlNodeList mynodelist = xmldoc.SelectNodes(xmlPathPattern);
foreach (XmlNode node in mynodelist)
{
XmlNode name = node.FirstChild;
name.Value = "asd";//here I am trying to change value
totalval = totalval + "Name=" + name.OuterXml + "\n";
}
xmldoc.Save(XmlFile);
print(totalval);
}
This is my .xml file.
<name>John</name>
I can successfully read the value but it is not changing the value from .xml file.After running the program it must be like this
<name>asd</name> .
Where is my mistake ?
Obviously, the XMLFile is not a file path, it is xml string. So, you should define a valid path to save it.
xmldoc.Save("samplefile.xml");
or if you want to set the XmlFile variable with modified xml;
XmlFile = xmldoc.OuterXml;
Complete codes look like;
void ParseXml(string XmlFile)
{
string totalval = "";
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(new StringReader(XmlFile));
string xmlPathPattern = "//name";
XmlNodeList mynodelist = xmldoc.SelectNodes(xmlPathPattern);
foreach (XmlNode node in mynodelist)
{
XmlNode name = node.FirstChild;
name.Value = "asd";//here I am trying to change value
totalval = totalval + "Name=" + name.OuterXml + "\n";
}
//XmlFile = xmldoc.OuterXml;
xmldoc.Save("samplefile.xml");
print(totalval);
}
If I'm not wrong - you need to fire disposable to save stream. Easiest way - wrap with using
void ParseXml(string XmlFile)
{
string totalval = "";
using(XmlDocument xmldoc = new XmlDocument())
{
xmldoc.Load(new StringReader(XmlFile));
string xmlPathPattern = "//name";
XmlNodeList mynodelist = xmldoc.SelectNodes(xmlPathPattern);
foreach (XmlNode node in mynodelist)
{
XmlNode name = node.FirstChild;
name.Value = "asd";//here I am trying to change value
totalval = totalval + "Name=" + name.OuterXml + "\n";
}
xmldoc.Save(XmlFile);
print(totalval);
}
}

XML file is overwritten in each run

I am trying to write some data into XML file.
Actually, I can do that, but in each run, the XML file is overwritten while I want it to add another row.
This is what I have done so far:
public static void StoreCustomerIntoXML(string Id)
{
string pth = System.Reflection.Assembly.GetCallingAssembly().CodeBase;
string actualPath = pth.Substring(0, pth.LastIndexOf("bin"));
string projectPath = new Uri(actualPath).LocalPath;
string reportPath = projectPath + "Customers\\CustomersListCreated.xml";
XmlDocument xmlDoc = new XmlDocument();
XmlNode rootNode = xmlDoc.CreateElement("Customers");
xmlDoc.AppendChild(rootNode);
XmlNode userNode = xmlDoc.CreateElement("Id");
userNode.InnerText = Id;
rootNode.AppendChild(userNode);
xmlDoc.Save(reportPath);
}
So calling the method for the first time will include Id = 1234
and the second run will include Id = 6543
The XML file will always include the Id of last run and only this Id.
Try this
public static void StoreCustomerIntoXML(string Id)
{
string pth = System.Reflection.Assembly.GetCallingAssembly().CodeBase;
string actualPath = pth.Substring(0, pth.LastIndexOf("bin"));
string projectPath = new Uri(actualPath).LocalPath;
string reportPath = projectPath + "CustomersListCreated.xml";
XmlDocument xmlDoc = new XmlDocument();
if (File.Exists(reportPath))
{
xmlDoc.Load(reportPath);
XmlNode rootNode = xmlDoc.DocumentElement;
xmlDoc.AppendChild(rootNode);
XmlElement elem = xmlDoc.CreateElement("Id");
elem.InnerText = Id;
rootNode.AppendChild(elem);
}
else
{
XmlNode rootNode = xmlDoc.CreateElement("Customers");
xmlDoc.AppendChild(rootNode);
XmlNode userNode = xmlDoc.CreateElement("Id");
userNode.InnerText = Id;
rootNode.AppendChild(userNode);
}
xmlDoc.Save(reportPath);
}
You could check if the file exists and load it using the method Load, instead of creating a new one every time you call your method.
public static void StoreCustomerIntoXML(string Id)
{
string pth = System.Reflection.Assembly.GetCallingAssembly().CodeBase;
string actualPath = pth.Substring(0, pth.LastIndexOf("bin"));
string projectPath = new Uri(actualPath).LocalPath;
string reportPath = projectPath + "Customers\\CustomersListCreated.xml";
XmlDocument xmlDoc;
if (File.Exists(reportPath))
xmlDoc = XDocument.Load(reportPath);
else
xmlDoc = new XmlDocument();
XmlNode rootNode = xmlDoc.CreateElement("Customers");
xmlDoc.AppendChild(rootNode);
XmlNode userNode = xmlDoc.CreateElement("Id");
userNode.InnerText = Id;
rootNode.AppendChild(userNode);
xmlDoc.Save(reportPath);
}
public static void StoreCustomerIntoXML(string Id)
{
string pth = System.Reflection.Assembly.GetCallingAssembly().CodeBase;
string actualPath = pth.Substring(0, pth.LastIndexOf("bin"));
string projectPath = new Uri(actualPath).LocalPath;
string reportPath = projectPath + "Customers\\CustomersListCreated.xml";
XmlDocument xmlDoc = new XmlDocument();
XmlNode rootNode;
if (File.Exists(reportPath))
{
xmlDoc.Load(reportPath);
rootNode = xmlDoc.DocumentElement;
}
else
{
rootNode = xmlDoc.CreateElement("Customers");
xmlDoc.AppendChild(rootNode);
}
XmlNode userNode = xmlDoc.CreateElement("Id");
userNode.InnerText = Id;
rootNode.AppendChild(userNode);
xmlDoc.Save(reportPath);
}

Generate One XML(LogData.xml) file from Two different Application Without Threading

I want to write XML Log File from two or more Application into LogData.xml file. while running the one application it creats the LogData.xml file correctly but at the same time both the allpication are run simulteniously and try to write the LogData.xml file it gives me an error message such as The process cannot access the file Log_Data.xml' because it is being used by another process.
I use this code
public void WriteXmlLog(string logType, string logFlag, string logModule, string logLocation, string logText, string logStackTrace)
{
if (!File.Exists(_logFilePath))
{
//File.WriteAllText(_logFilePath, "<?xml version='1.0' encoding='utf-8' standalone='yes'?>\r\n<AppXmlLogWritter></AppXmlLogWritter>");
XmlTextWriter textWritter = new XmlTextWriter(_logFilePath, null);
textWritter.WriteStartDocument();
textWritter.WriteStartElement("AppXmlLogWritter");
textWritter.WriteEndElement();
textWritter.Close();
}
XmlDocument xmlDoc = new XmlDocument();
using (FileStream fileStream = new FileStream(_logFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
{
string currentDateTime = DateTime.Now.ToString("yyyyMMddHHmmss");
xmlDoc.Load(fileStream);
XmlElement newelement = xmlDoc.CreateElement("LogData");
XmlElement xmlLogID = xmlDoc.CreateElement("LogID");
XmlElement xmlLogDateTime = xmlDoc.CreateElement("LogDateTime");
XmlElement xmlLogType = xmlDoc.CreateElement("LogType");
XmlElement xmlLogFlag = xmlDoc.CreateElement("LogFlag");
XmlElement xmlLogApplication = xmlDoc.CreateElement("LogApplication");
XmlElement xmlLogModule = xmlDoc.CreateElement("LogModule");
XmlElement xmlLogLocation = xmlDoc.CreateElement("LogLocation");
XmlElement xmlLogText = xmlDoc.CreateElement("LogText");
XmlElement xmlLogStackTrace = xmlDoc.CreateElement("LogStackTrace");
xmlLogID.InnerText = _logIDPrefix + currentDateTime + randomNumber;
xmlLogDateTime.InnerText = currentDateTime;
xmlLogType.InnerText = ((LogTypes)Convert.ToInt32(logType)).ToString();
xmlLogFlag.InnerText = logFlag;
xmlLogApplication.InnerText = _logApplication;
xmlLogModule.InnerText = logModule;
xmlLogLocation.InnerText = logLocation;
xmlLogText.InnerText = logText;
xmlLogStackTrace.InnerText = logStackTrace;
newelement.AppendChild(xmlLogID);
newelement.AppendChild(xmlLogDateTime);
newelement.AppendChild(xmlLogType);
newelement.AppendChild(xmlLogFlag);
newelement.AppendChild(xmlLogApplication);
newelement.AppendChild(xmlLogModule);
newelement.AppendChild(xmlLogLocation);
newelement.AppendChild(xmlLogText);
xmlDoc.DocumentElement.AppendChild(newelement);
//}
//finally
//{
// objMutex.ReleaseMutex();
//}
}
xmlDoc.Save(_logFilePath);
}
I want to achive this without Threading
Perhaps try implementing logging with NLog in both applications and set as the target the same xml.

Run time XML creation in c# and saving the data

Trying to create dynamic XML file and save the data to it, however i am able to save the last entry and not all the entries. Any thoughts?
To generate XML file with needed nodes:
GenerateXML()
XmlDocument doc = new XmlDocument();
XmlNode docNode = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
doc.AppendChild(docNode);
XmlNode albums = doc.CreateElement("albums");
doc.AppendChild(albums);
XmlNode album = doc.CreateElement("album");
albums.AppendChild(album);
XmlNode title = doc.CreateElement("title");
albums.AppendChild(title);
doc.Save(System.Windows.Forms.Application.StartupPath + "\\albums.xml");
The output from button click gives me either 10 records or 100 records or some number of records:
//album is a class returned by web service
if (Elements.Count > 0)
{
string path = System.Windows.Forms.Application.StartupPath + "\\albums.xml";
//Read the file stream in read mode
FileStream READER = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
System.Xml.XmlDocument albumSpecs = new System.Xml.XmlDocument();
albumSpecs.Load(READER);
FileStream WRITER = null;
GenerateXML();
//Create a FileStream for writing
WRITER = new FileStream(path, FileMode.Open, FileAccess.Write, FileShare.ReadWrite);
XmlElement root = doc.DocumentElement;
XmlNodeList nodes = root.SelectNodes("//albums");
for (int i = 0; i < ResultsList.Items.Count - 1; i++)
{
album = (Album)ResultsList.Items[i];
foreach (XmlNode node in nodes)
{
node["title"].InnerText = album.Title;
}
}
//Write the data to the filestream
doc.Save(WRITER);
}
I get the last entry data in the XML and not all the entries returned.
<?xml version="1.0" encoding="UTF-8"?>
<albums>
<album />
<title>She will be loved</title>
</albums>
How do i build run time XML based on the # of entries returned?
First load already saved xml into XmlDocument and then add new elements into it ...
GenerateXML()
string xmlFilePath = Path.Combine(System.Windows.Forms.Application.StartupPath, "albums.xml");
XmlDocument doc = new XmlDocument();
XmlNode albums = null;
if (!File.Exists(xmlFilePath))
{
XmlNode docNode = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
doc.AppendChild(docNode);
albums = doc.CreateElement("albums");
doc.AppendChild(albums);
}
else
{
doc.Load(xmlFilePath);
albums = doc.ChildNodes[1];
}
XmlNode album = doc.CreateElement("album");
albums.AppendChild(album);
XmlNode albumName = doc.CreateElement("name");
album.AppendChild(albumName);
XmlNode title = doc.CreateElement("title");
album.AppendChild(title);
doc.Save(xmlFilePath);
Try adding elements to your XML document ?
for (int i = 0; i < ResultsList.Items.Count - 1; i++)
{
album = (Album)ResultsList.Items[i];
foreach (XmlNode node in nodes)
{
node["title"].InnerText = album.Title;
}
}
This sample of code isnt doing much, because you only have one element to iterate on ...
Edit :
I imagine you want to do something like this :
for(int i = 0; i < ResultsList.Items.count -1; i++)
{
XmlNode child = doc.createElement("Title");
doc.AppendChild .....
}
doc.save;

Modifying InnerXml of a text XmlNode

I traverse an html document with SGML and XmlDocument. When I find an XmlNode which its type is Text, I need to change its value that has an xml element. I can't change InnerXml because it's readonly. I tried to change InnerText, but this time tag descriptor chars < and > encoded to < and >. for example:
<p>
This is a text that will be highlighted.
<anothertag />
<......>
</p>
I'm trying to change to:
<p>
This is a text that will be <span class="highlighted">highlighted</span>.
<anothertag />
<......>
</p>
What is the easiest way to modify the value of a text XmlNode?
I have a workaround, I don't know it is a real solution or what, but it can result what I want. Please comment for this code if it is worthy solution or not
private void traverse(ref XmlNode node)
{
XmlNode prevOldElement = null;
XmlNode prevNewElement = null;
var element = node.FirstChild;
do
{
if (prevNewElement != null && prevOldElement != null)
{
prevOldElement.ParentNode.ReplaceChild(prevNewElement, prevOldElement);
prevNewElement = null;
prevOldElement = null;
}
if (element.NodeType == XmlNodeType.Text)
{
var el = doc.CreateElement("text");
//Here is manuplation of the InnerXml.
el.InnerXml = element.Value.Replace(a_search_term, "<b>" + a_search_term + "</b>");
//I don't replace element right now, because element.NextSibling will be null.
//So I replace the new element after getting the next sibling.
prevNewElement = el;
prevOldElement = element;
}
else if (element.HasChildNodes)
traverse(ref element);
}
while ((element = element.NextSibling) != null);
if (prevNewElement != null && prevOldElement != null)
{
prevOldElement.ParentNode.ReplaceChild(prevNewElement, prevOldElement);
}
}
Also, I remove <text> and </text> strings after the traverse function:
doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.XmlResolver = null;
doc.Load(sgmlReader);
var html = doc.FirstChild;
traverse(ref html);
textBox1.Text = doc.OuterXml.Replace("<text>", String.Empty).Replace("</text>", String.Empty);
using System;
using System.Xml;
public class Sample {
public static void Main() {
XmlDocument doc = new XmlDocument();
doc.LoadXml(
"<p>" +
"This is a text that will be highlighted." +
"<br />" +
"<img />" +
"</p>");
string ImpossibleMark = "_*_";
XmlNode elem = doc.DocumentElement.FirstChild;
string thewWord ="highlighted";
if(elem.NodeType == XmlNodeType.Text){
string OriginalXml = elem.ParentNode.InnerXml;
while(OriginalXml.Contains(ImpossibleMark)) ImpossibleMark += ImpossibleMark;
elem.InnerText = elem.InnerText.Replace(thewWord, ImpossibleMark);
string replaceString = "<span class=\"highlighted\">" + thewWord + "</span>";
elem.ParentNode.InnerXml = elem.ParentNode.InnerXml.Replace(ImpossibleMark, replaceString);
}
Console.WriteLine(doc.DocumentElement.InnerXml);
}
}
The InnerText property will give you the text content of all the child nodes of the XmlNode. What you really want to set is the InnerXml property, which will be construed as XML, not as text.

Categories

Resources