Xml serialization and empty file - c#

I stomped on some very weird bug which is very hard to reproduce I literally cant reproduce it. We have a window service installed on around 300+ PCs. From time to time config file(xml) that is used by this service become clear (on some of them). Totally clear no xml tags, nothing, 0kb. I have no clue what can cause such problem. No exception is logged in our logs. Even after this config becoming clear it's still running however it's not communicating with our web service. This is the class that is used for xml serialization and deserialization. I can’t find what can be possibly causing such behavior. Of course problem might not be in this particular class. Any suggestions?? Maybe some hints what can cause a file to become clear. When any operation on this file is by using this class.
Sorry for my bad English.
[XmlRootAttribute("xmlconfig", Namespace = "DSD_Config", IsNullable = false)]
public class xmlconfig
{
[XmlElementAttribute(IsNullable = false)]
public string ProgramApteczny { get; set; }
public string Server { get; set; }
public string Database { get; set; }
public string User { get; set; }
public string Password { get; set; }
public string DSDUser { get; set; }
public string DSDPassword { get; set; }
public string DSDServerAdres { get; set; }
//public static string cofFile = System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\DSD_Agent\\config.xml";
public static string cofFile = Application.StartupPath + "\\config.xml";
public xmlconfig()
{
}
public xmlconfig(string sProgramApteczny, string sServer, string sDatabase, string sUser, string sPassword, string sDSDUser, string sDSDPassword, string sDSDServerAdres)
{
ProgramApteczny = sProgramApteczny;
Server = sServer;
Database = sDatabase;
User = sUser;
Password = sPassword;
DSDUser = sDSDUser;
DSDPassword = sDSDPassword;
DSDServerAdres = sDSDServerAdres;
}
public static void readXMLConfig(out xmlconfig configFile)
{
XmlSerializer oSerializer = new XmlSerializer(typeof(xmlconfig));
configFile = new xmlconfig();
try
{
using (FileStream fs = new FileStream(cofFile, FileMode.Open, FileAccess.Read))
{
configFile = (xmlconfig)oSerializer.Deserialize(fs);
try
{
configFile.Password = Encryption.DecryptString(configFile.Password);
}
catch (Exception)
{
configFile.Password = configFile.Password;
}
try
{
configFile.DSDPassword = Encryption.DecryptString(configFile.DSDPassword);
}
catch (Exception)
{
configFile.DSDPassword = configFile.DSDPassword;
}
}
}
catch
{
configFile = null;
}
}
public static void writeXMLConfig(string sProgramApteczny, string sServer, string sDatabase, string sUser, string sPassword, string sDSDUser, string sDSDPassword)
{
xmlconfig oxmlconfig = new xmlconfig();
readXMLConfig(out oxmlconfig);
sPassword = Encryption.EncryptString(sPassword);
sDSDPassword = Encryption.EncryptString(sDSDPassword);
if (oxmlconfig == null)
{
oxmlconfig = new xmlconfig(sProgramApteczny, sServer, sDatabase, sUser, sPassword, sDSDUser, sDSDPassword, "");
}
else
{
oxmlconfig.ProgramApteczny = sProgramApteczny;
oxmlconfig.Server = sServer;
oxmlconfig.Database = sDatabase;
oxmlconfig.User = sUser;
oxmlconfig.Password = sPassword;
oxmlconfig.DSDUser = sDSDUser;
oxmlconfig.DSDPassword = sDSDPassword;
}
XmlSerializer oSerializer = new XmlSerializer(typeof(xmlconfig));
TextWriter oStreamWriter = null;
try
{
oStreamWriter = new StreamWriter(cofFile, false);
oSerializer.Serialize(oStreamWriter, oxmlconfig);
}
catch (Exception oException)
{
WriteToLog(DateTime.Now, "Aplikacja wygenerowała następujący wyjątek: " + oException.Message);
// Console.WriteLine("Aplikacja wygenerowała następujący wyjątek: " + oException.Message);
}
finally
{
if (null != oStreamWriter)
{
oStreamWriter.Close();
}
}
}
public static void writeXMLDSDConfig(string sDSDServerAdres)
{
xmlconfig oxmlconfig = new xmlconfig();
readXMLConfig(out oxmlconfig);
if (oxmlconfig == null)
{
throw new Exception("Aplikacja wygenerowała następujący wyjątek: Musisz zdefiniować wszystkie parametry");
}
else
{
oxmlconfig.DSDPassword = Encryption.EncryptString(oxmlconfig.DSDPassword);
oxmlconfig.Password = Encryption.EncryptString(oxmlconfig.Password);
oxmlconfig.DSDServerAdres = sDSDServerAdres;
}
XmlSerializer oSerializer = new XmlSerializer(typeof(xmlconfig));
TextWriter oStreamWriter = null;
try
{
oStreamWriter = new StreamWriter(cofFile, false);
oSerializer.Serialize(oStreamWriter, oxmlconfig);
}
catch (Exception oException)
{
throw new Exception("Aplikacja wygenerowała następujący wyjątek: " + oException.Message);
}
finally
{
if (null != oStreamWriter)
{
oStreamWriter.Close();
}
}
}
}

What I guess, the xml file is accessed by multiple computers/windows services; if so?
Looks no locking mechanism is being used while reading and writing the file. a possible work around would be using a single instance class that only allows one thread to read/write file at one time.
bool isInProgress=false
Public void Read()
{
if(isInProgress==false)
{
isInProgress=true;
try
{
//Do reading or writing
}
finally
{
isInProgress=false;
}
}
}

Related

Call db connectivity values from a file

I am fairly new to c# and would like to know how values can be called from a file instead of statically hard coding it in the class. I know in java spring boot applications we can have it in application.properties files. In my case I have the db hostname, username and pwd stored in a file
namespace NunitTestCase
{
[TestFixture]
public class Test
{
string query = "SELECT * FROM SYSTEM.ADMIN.EMPLOYEE";
string host = "vm1.test.app.com"; //want these data in a file
int port = 5480;
string dbName = "SYSTEM";
string userName = "admin";
string password = "password";
[Test]
public void TestCase()
{
var builder = new ConnectionStringBuilder();
builder.UserName = userName;
builder.Password = password;
builder.Port = port;
builder.Host = host;
builder.Database = dbName;
using (var con = new Connection(builder.ConnectionString))
{
con.Open();
NUnit.Framework.Assert.That(con.State == ConnectionState.Open);
using (var cmd = new Command(query, con))
{
var rdr = cmd.ExecuteReader();
while (rdr.Read())
{
for (int i = 0; i < rdr.FieldCount; i++)
{
object o = null;
try
{
o = rdr.GetValue(i);
}
catch (Exception ex)
{
o = ex.Message;
}
Console.WriteLine(o);
}
}
}
con.Close();
NUnit.Framework.Assert.That(con.State == ConnectionState.Closed);
}
}
}
}
file.yaml
database:
host: "vm1.test.app.com"
port: 5480
dbName: "SYSTEM"
userName: "admin"
password: "password"
How do I make changes in my code so that instead of hardcoding, these values can be picked up from the file
Traditionally, in .net we store configuration in .json/.xml files and C# supports built-in functionality to parse it, but as far as you are using .YAML file you can install the library to parse this file:
YAMLDotNet
and use this to parse.
public class Database {
public string Host { get; set; }
public string Port { get; set; }
public string DbName { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
}
public class Configuration
{
public Database Database { get; set; }
}
var yamlString = File.ReadAllText(#"...\file.yaml");
var deserializer = new DeserializerBuilder().WithNamingConvention(new CamelCaseNamingConvention()).Build();
var config = deserializer.Deserialize<Configuration>(yamlString);
If you don't want to use any libraries you can parse it manually, so create a class which reflects your model in YAML, something like:
Function to get the value of a property:
public string GetValueOfPropertyYaml(string yamlStr) {
return yamlStr?.Split(":")?.Skip(1)?.FirstOrDefault()?.Trim() ?? string.Empty;
}
Main code:
string[] yamlStringArray = File.ReadAllLines(#"..\file.yaml");
var config = new Database();
foreach (var yamlStr in yamlStringArray) {
if (yamlStr.Contains("host:")) {
config.Host = GetValueOfPropertyYaml(yamlStr);
}
if (yamlStr.Contains("port:"))
{
config.Port = GetValueOfPropertyYaml(yamlStr);
}
if (yamlStr.Contains("dbName:"))
{
config.DbName = GetValueOfPropertyYaml(yamlStr);
}
if (yamlStr.Contains("userName:"))
{
config.UserName = GetValueOfPropertyYaml(yamlStr);
}
if (yamlStr.Contains("password:"))
{
config.Password = GetValueOfPropertyYaml(yamlStr);
}
}
;
// use filled `config` variable below.
your model:
public class Database
{
public string Host { get; set; }
public string Port { get; set; }
public string DbName { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
}
NOTE: I highly recommend you to use library, because it was already tested and worked perfectly(my method should be tested properly)

System.InvalidOperationException: 'There is an error in the XML document (1, 1).'

This error is showing up in my code, there is a second one that is as follows:
XmlException: The existing data at the root level is invalid. Line 1, position 1
I checked this second one saying there is a error with the file when there isn't any since I have 5 files inside my XMLFiles directory.
public static void Main()
{
XmlSerializer serializer = new XmlSerializer(typeof(ImportSession));
MemoryStream stream = new MemoryStream();
using (StreamWriter sw = new StreamWriter(stream))
{
sw.Write(stream);
sw.Flush();
stream.Position = 0;
}
Console.ReadKey();
foreach (string filename in Directory.EnumerateFiles(#"C:\XMLFiles", "*.xml"))
{
ProcessFile(filename, stream, serializer);
}
void ProcessFile(string Filename, MemoryStream stream, XmlSerializer serializer)
{
bool temErro = false;
Console.WriteLine("A processar xml: " + Filename);
XmlDocument xml = new XmlDocument();
xml.Load(Filename);
ImportSession session = (ImportSession)serializer.Deserialize(stream);
foreach (Batch batch in session.Batches)
{
foreach (Document doc in batch.Documents)
{
foreach (Page page in doc.Pages)
{
if (!string.IsNullOrEmpty(batch.Processed.ToString()))
{
if (!string.IsNullOrEmpty(page.HasError.ToString()))
{
string Import = page.ImportFileName;
Console.WriteLine("Página com erro:" + Import);
temErro = true;
}
}
}
}
}
if (temErro)
Console.WriteLine("Ficheiro com erro: " + Filename);
else
Console.WriteLine("Ficheiro processado: " + Filename);
Console.WriteLine(Filename);
}
}
public class ImportSession
{
public Batch[] Batches { get; set; }
}
public class Batch
{
[XmlAttribute]
public string Name { get; set; }
[XmlAttribute]
public string Description { get; set; }
[XmlAttribute]
public string BatchClassName { get; set; }
[XmlAttribute]
public bool Processed { get; set; }
public Document[] Documents { get; set; }
}
public class Document
{
[XmlAttribute]
public string FormTypeName { get; set; }
public IndexField[] IndexFields { get; set; }
public Page[] Pages { get; set; }
}
public class IndexField
{
[XmlAttribute]
public string Name { get; set; }
[XmlAttribute]
public string Value { get; set; }
}
public class Page
{
[XmlAttribute]
public string ImportFileName { get; set; }
[XmlAttribute]
public string ErrorCode { get; set; }
[XmlAttribute]
public string ErrorMessage { get; set; }
[XmlIgnore]
public bool HasError => !string.IsNullOrWhiteSpace(ErrorMessage);
}
This app right now is only trying to read all the files and point out some parts that need to show up in the console and it was doing it but I was adviced on here to change into this object oriented and memory stream.
This:
MemoryStream stream = new MemoryStream();
using (StreamWriter sw = new StreamWriter(stream))
{
sw.Write(stream);
sw.Flush();
stream.Position = 0;
is basically meaningless. Whatever the contents of stream are meant to be: it isn't this. Ask yourself:
What is stream meant to contain?
At the moment it contains... itself, sort of, but not really?
If you intend the stream to be the file contents: just use File.OpenRead
I think this is based on a misunderstanding from answers to previous questions on the topic.
This should make it work. BUT keep in mind, that it is in no way production-ready.
public static void Main()
{
XmlSerializer serializer = new XmlSerializer(typeof(ImportSession));
foreach (string filename in Directory.EnumerateFiles(#"C:\XMLFiles", "*.xml"))
{
ProcessFile(filename, serializer);
}
Console.ReadKey();
}
private static void ProcessFile(string Filename, XmlSerializer serializer)
{
bool temErro = false;
Console.WriteLine("A processar xml: " + Filename);
using (var file = File.OpenRead(Filename)) {
var session = (ImportSession)serializer.Deserialize(file);
// from here on the rest of your code ...
To minimize the code that keeps the file opened:
ImportSession session;
using (var file = File.OpenRead(Filename))
{
session = (ImportSession)serializer.Deserialize(file);
}
// file will be closed by disposal of FileStream using this notation
// rest of code
Addendum
if (!string.IsNullOrEmpty(batch.Processed.ToString()))
{ // Will ALWAYS be entered!
if (!string.IsNullOrEmpty(page.HasError.ToString()))
{ // Will ALWAYS be entered!
string Import = page.ImportFileName;
Console.WriteLine("Página com erro:" + Import);
temErro = true;
}
}
Let's look at it:
!string.IsNullOrEmpty(page.HasError.ToString()) is always true. Why?
page.HasError is of type bool. So, page.HasError.ToString() "Converts the value of this instance to its equivalent string representation (either "True" or "False")."
So, it will never be null or empty. So, string.IsNullOrEmpty will always be false, and !string.IsNullOrEmpty therefore always be true.
If you want to check the boolean value, you simply do if( page.HasError ) => "Page has an error"

System.Xml.XmlException 'Data at the root level is invalid, line 1, position 1' error is showing up when i changed from 1 xml file to 5

Hello everyone recently i have been making a c# app to read a xml file and it worked but now i was tasked with making it do that and read certain nodes from multiple xml files inside a certain folder and now i doesen´t work and shows that error in the title.
using System;
using System.Xml;
using System.IO;
namespace XmlReaderConsoleAPP
{
class Program
{
static void Main()
{
ProcessFile(#"C:\XMLFiles\SaintGobain_Pam_20210118.xml");
try
{
var path = #"C:\XMLFiles\SaintGobain_Pam_20210118.xml";
DirectoryInfo di = new DirectoryInfo(path);
foreach (var file in Directory.GetFiles(path))
{
}
Console.ReadKey();
}
catch(Exception ex)
{
Console.WriteLine("Erro: {0}", ex.Message);
return;
}
static void ProcessFile(string Filename)
{
XmlDocument xml = new XmlDocument();
xml.LoadXml(Filename);
XmlNodeList xnLista = xml.SelectNodes(#"//ImportSession/Batches/batch/Documents/Document/Pages/Page");
Console.WriteLine($"Selected {xnLista.Count} nodes");
int i = 0;
foreach (XmlNode xn in xnLista)
{
Console.WriteLine($"{++i} {xn.Name}: {xn.Attributes["ImportFileName"].Value}");
}
XmlNodeList xnLista2 = xml.SelectNodes(#"//IndexFields/IndexField");
Console.WriteLine($"Selected {xnLista2.Count} nodes");
int j = 0;
foreach (XmlNode xn in xnLista2)
{
Console.WriteLine($"{++j} {xn.Name}: {xn.Attributes["Value"].Value}");
//string error = xn.Attributes["ErrorMessage"]?.Value;
//if (string.IsNullOrEmpty(error))
//{
//}
//elsex
//{
//}
}
Console.WriteLine(Filename);
}
}
}
}
If you guys find the error help me out cause i need it.
Ps: the xml files follow the same roots ImportSession/Batches/Batch/Documents/Document/Pages/Page
Let's first clean up a little:
namespace XmlReaderConsoleAPP
{
class Program
{
static void Main()
{
var path = #"C:\XMLFiles";
var filter = #"*.xml"; // Add filter to only enumerate .xml files
foreach (var file in Directory.EnumerateFiles(path, filter))
{
// Move try/catch inside the loop to skip errornous files.
try
{
ProcessFile( file );
}
catch(Exception ex) // Usually, try to catch the specific as possible
{
Console.WriteLine("Error: {0} {1}in File {2}",
ex.Message, Environment.NewLine, file);
}
}
Console.ReadKey();
}
} // End of Main
static void ProcessFile(string Filename)
{
XmlDocument xml = new XmlDocument();
xml.LoadXml(Filename);
XmlNodeList xnLista = xml.SelectNodes(#"//ImportSession/Batches/batch/Documents/Document/Pages/Page");
Console.WriteLine($"Selected {xnLista.Count} nodes");
int i = 0;
foreach (XmlNode xn in xnLista)
{
Console.WriteLine($"{++i} {xn.Name}: {xn.Attributes["ImportFileName"].Value}");
}
XmlNodeList xnLista2 = xml.SelectNodes(#"//IndexFields/IndexField");
Console.WriteLine($"Selected {xnLista2.Count} nodes");
int j = 0;
foreach (XmlNode xn in xnLista2)
{
Console.WriteLine($"{++j} {xn.Name}: {xn.Attributes["Value"].Value}");
}
Console.WriteLine(Filename);
}
} // class
} // namespace
Next: System.Xml.XmlException means there is something wrong with the xml input file.
What can you do about that?
Skip it, so the others may still be processed. Log the error, so you can later deep dive into the file, or request it be fixed and sent again.
If you have an XML Schema, you can validate the xml and easier find what exactly is wrong. See XML schema (XSD) validation with XmlSchemaSet and/or XmlDocument.Validate Method.
You can examine the input file manually and find the error. Mind that the message may sometimes be deceiving. I'd start with checking if it is well-formed and valid xml (there are tools for that).
I was able to resolve the problem with objects and their serialization.
You can find a way to do it with these two posts:
Objects:https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/objects
Objects serialization:https://learn.microsoft.com/en-us/dotnet/standard/serialization/how-to-serialize-an-object
Giving some more context.
Start by making empty strings at the start of the method you're doing, it being a foreach loop or a if statement
class Program
{
static DataAccess da = new DataAccess();
public static void Main()
{
XmlSerializer serializer = new XmlSerializer(typeof(ImportSession));
foreach (string filename in Directory.EnumerateFiles(Properties.Settings.Default.PastaXML, "*.xml"))
{
string fName = "";
string BatchCName = "";
string batchName = "";
string description = "";
ProcessFile(filename, serializer, fName, BatchCName, batchName, description );
}
Console.ReadKey();
}
}
After that start in my case my processfile function
private static void ProcessFile(string filename, XmlSerializer serializer, string fName, string batchName, string description, string BatchCName)
{
Console.WriteLine("A processar xml: " + filename);
bool temErro = false;
using (FileStream file = File.OpenRead(filename))
{
var session = (ImportSession)serializer.Deserialize(file);
foreach (Batch batch in session.Batches)
{
fName = Path.GetFileName(filename);
BatchCName = batch.BatchClassName;
batchName = batch.Name;
description = batch.Description;
foreach (Document doc in batch.Documents)
{
foreach (Page page in doc.Pages)
{
# if (!string.IsNullOrEmpty(batch.Processed.ToString()))
{
if (page.HasError)
{
string Import = page.ImportFileName;
Console.WriteLine("Página com erro:" + Import + fName);
temErro = true;
da.SP_Insert(filename,fName,BatchCName,batchName,description,1,Import,0, "");
There are two if statements inside this processfile that run checks on if there is a error inside the file and if the file as already been processed.
I also added Insert into a stored procedure to make sure everything is complete in this edit I'm making.
The objects I used are as follows
public class ImportSession
{
public Batch[] Batches { get; set; }
}
public class Batch
{
[XmlAttribute]
public string Name { get; set; }
[XmlAttribute]
public string Description { get; set; }
[XmlAttribute]
public string BatchClassName { get; set; }
[XmlAttribute]
public bool Processed { get; set; }
public Document[] Documents { get; set; }
}
public class Document
{
[XmlAttribute]
public string FormTypeName { get; set; }
public IndexField[] IndexFields { get; set; }
public Page[] Pages { get; set; }
}
public class IndexField
{
[XmlAttribute]
public string Name { get; set; }
[XmlAttribute]
public string Value { get; set; }
}
public class Page
{
[XmlAttribute]
public string ImportFileName { get; set; }
[XmlAttribute]
public string ErrorCode { get; set; }
[XmlAttribute]
public string ErrorMessage { get; set; }
[XmlIgnore]
public bool HasError => !string.IsNullOrWhiteSpace(ErrorMessage);
}
And my stored procedure insert in case any of you are wondering how to do it
public void SP_Insert(string XMLPath, string XMLName, string BatchClassName, string BatchName,
string BatchDescription, int Error, string ErrorImagePath, int Done, string DonePath)
{
try
{
ManageConnectionState();
SqlCommand command = new SqlCommand("Sp_Insert", connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("#XMLPath",SqlDbType.NText).Value = XMLPath;
command.Parameters.Add("#XMLName",SqlDbType.NText).Value = XMLName;
command.Parameters.Add("#BatchClassName",SqlDbType.NText).Value= BatchClassName;
command.Parameters.Add("#BatchName",SqlDbType.NText ).Value = BatchName;
command.Parameters.Add("#BatchDescription", SqlDbType.NText ).Value = BatchDescription;
command.Parameters.Add("#Error",SqlDbType.Bit).Value = Error;
command.Parameters.Add("#ErrorImagePath", SqlDbType.NText).Value = ErrorImagePath;
command.Parameters.Add("#Done", SqlDbType.Bit ).Value=Done;
command.Parameters.Add("#DonePath", SqlDbType.NText).Value = DonePath;
command.ExecuteScalar();
}
catch (Exception ex)
{
Console.WriteLine("Erro: " + ex.Message);
}
finally
{
ManageConnectionState();
connection.Close();
}
}
Please comment if you don´t understand something ill help out.

Csv Helper. First Value is shifting to the right

I have been trying to create a simple csv file using the csv helper. However, the result, I am getting is not what I expected.
For some reason which I cannot find it, the first value is shifting towards the right and appear as the header.
Could someone point me what I am doing wrong here?
public class Record
{
public string Vrm { get; set; }
public string Version { get; set; }
public DateTime Started { get; set; }
public DateTime? Completed { get; set; }
public string Status { get; set; }
public string Comments { get; set; }
}
static void Main(string[] args)
{
var source = new List<Record> {
new Record {
Status = "Success",
Version = "enhance",
Started = DateTime.Parse("2017-11-15 13:27:56.9933333"),
Completed = DateTime.Parse("2017-11-15 13:27:57.7300000"),
Vrm = "16aux",
Comments = "Completed Successfully"
}
};
var month = DateTime.UtcNow.Month;
var year = DateTime.UtcNow.Year;
var fileName = $"TestFile_{month}{year}.csv";
using (var sw = new StreamWriter(fileName))
{
var writer = new CsvWriter(sw);
try
{
writer.WriteHeader<Record>();
foreach (var record in source)
{
writer.WriteField(record.Vrm);
writer.WriteField(record.Version);
writer.WriteField(record.Started);
writer.WriteField(record.Completed);
writer.WriteField(record.Status);
writer.WriteField(record.Comments);
writer.NextRecord();
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
var i = sw;
}
}
The result is something like this:
Read up on http://joshclose.github.io/CsvHelper/writing#writing-all-records
You need to advance the writer one line by calling writer.NextRecord(); after writer.WriteHeader<Record>();.
You could also simply write all data at once, using csv.WriteRecords( records ); instead of foreaching over them

How can I serialize a List<> of classes that I've created

I have the following code:
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
{
saveFileDialog.AddExtension = true;
saveFileDialog.DefaultExt = ".xml";
var resultDialog = saveFileDialog.ShowDialog(this);
if (resultDialog == System.Windows.Forms.DialogResult.OK)
{
string fileName = saveFileDialog.FileName;
SerializeObject(ListaDeBotoes, fileName);
}
}
public void SerializeObject(List<MyButton> serializableObjects, string fileName)
{
if (serializableObjects == null) { return; }
try
{
XmlDocument xmlDocument = new XmlDocument();
XmlSerializer serializer = new XmlSerializer(serializableObjects.GetType());
using (MemoryStream stream = new MemoryStream())
{
serializer.Serialize(stream, serializableObjects);
stream.Position = 0;
xmlDocument.Load(stream);
xmlDocument.Save(fileName);
stream.Close();
}
}
catch (Exception ex)
{
//Log exception here
}
}
My objective is to save this list of MyButtons, that is my own class (it is a control too if this matter), in a way that i could re-open it on the future. But this way is not working it stops at: XmlSerializer serializer = new XmlSerializer(serializableObjects.GetType()); and the catch exception is called... Any suggestions?
Try this....
Usings.....
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
Functions....
private void Serialize<T>(T data)
{
// Use a file stream here.
using (TextWriter WriteFileStream = new StreamWriter("test.xml"))
{
// Construct a SoapFormatter and use it
// to serialize the data to the stream.
XmlSerializer SerializerObj = new XmlSerializer(typeof(T));
try
{
// Serialize EmployeeList to the file stream
SerializerObj.Serialize(WriteFileStream, data);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("Failed to serialize. Reason: {0}", ex.Message));
}
}
}
private T Deserialize<T>() where T : new()
{
//List<Employee> EmployeeList2 = new List<Employee>();
// Create an instance of T
T ReturnListOfT = CreateInstance<T>();
// Create a new file stream for reading the XML file
using (FileStream ReadFileStream = new FileStream("test.xml", FileMode.Open, FileAccess.Read, FileShare.Read))
{
// Construct a XmlSerializer and use it
// to serialize the data from the stream.
XmlSerializer SerializerObj = new XmlSerializer(typeof(T));
try
{
// Deserialize the hashtable from the file
ReturnListOfT = (T)SerializerObj.Deserialize(ReadFileStream);
}
catch (Exception ex)
{
Console.WriteLine(string.Format("Failed to serialize. Reason: {0}", ex.Message));
}
}
// return the Deserialized data.
return ReturnListOfT;
}
// function to create instance of T
public static T CreateInstance<T>() where T : new()
{
return (T)Activator.CreateInstance(typeof(T));
}
Usage....
Serialize(dObj); // dObj is List<YourClass>
List<YourClass> deserializedList = Deserialize<List<YourClass>>();
Your object will be written\read to\from a file called test.xml that you can modify to suit....
Hope that helps....
/////////////////////////////////////////////////////////////////////////
An example class to hold your values for each MyButton object might look something like this......
public partial class PropertiesClass
{
public string colorNow { get; set; } = ColorTranslator.ToHtml(Color.FromArgb(Color.Black.ToArgb()));
public string backgroundColor { get; set; } = ColorTranslator.ToHtml(Color.FromArgb(Color.Black.ToArgb()));
public string externalLineColor { get; set; } = ColorTranslator.ToHtml(Color.FromArgb(Color.DarkBlue.ToArgb()));
public string firstColor { get; set; } = ColorTranslator.ToHtml(Color.FromArgb(Color.Goldenrod.ToArgb()));
public string secondColor { get; set; } = ColorTranslator.ToHtml(Color.FromArgb(Color.DarkGoldenrod.ToArgb()));
public string mouseEnterColor { get; set; } = ColorTranslator.ToHtml(Color.FromArgb(Color.PaleGoldenrod.ToArgb()));
public string doubleClickColor { get; set; } = ColorTranslator.ToHtml(Color.FromArgb(Color.Gold.ToArgb()));
public bool shouldIChangeTheColor { get; set; } = true;
public bool selectedToMove { get; set; } = true;
public bool selectedToLink { get; set; } = true;
}
Usage...
List<PropertiesClass> PropertiesClasses = new List<PropertiesClass>();
PropertiesClass PropertiesClass = new PropertiesClass();
PropertiesClasses.Add(PropertiesClass);
Serialize(PropertiesClasses);
If thats not a homework or study stuff you better use Json.NET to serialize your classes. Reinvent the well is probably gonna cost you more time.

Categories