Using BinaryFormatter to serialize a String[] variable within a class - c#

I am trying to move the m_settings variable from the volatile to the persistent records. I have tried adding the [serializable] attribute to the class and sending the m_settings variable to a file stream using a BinaryFormatter but I got an error saying that the file cannot be written, access to the file is denied. What am I doing wrong?
[Serializable]
public class SettingsComponent : GH_Component
{
public SettingsComponent(): base("LoadSettings", "LoadSettings", "Loading ini", "Extra", "Silkworm") { }
public override void CreateAttributes()
{
m_attributes = new SettingsComponentAttributes(this);
}
string m_settings_temp;
string[] m_settings;
public void ShowSettingsGui()
{
var dialog = new OpenFileDialog { Filter = "Data Sources (*.ini)|*.ini*|All Files|*.*" };
if (dialog.ShowDialog() != DialogResult.OK) return;
m_settings_temp = File.ReadAllText(dialog.FileName);
m_settings = m_settings_temp.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
ExpireSolution(true);
}
protected override void SolveInstance(IGH_DataAccess DA)
{
if (m_settings == null)
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "You must declare some valid settings");
return;
}
else
{
FileStream fs = new FileStream("DataFiletemp.dat", FileMode.Create);
BinaryFormatter formatter = new BinaryFormatter();
try
{
formatter.Serialize(fs, m_settings);
}
catch (SerializationException e)
{
Console.WriteLine("Failed to serialize. Reason: " + e.Message);
throw;
}
finally
{
fs.Close();
}
DA.SetDataList(0, m_settings);
}
}

Arthur, if your m_settings object is not complex you can use project settings (application or user level). Here is sample code how you can save some project settings to app.config:
[YourNamespace].Properties.Settings.Default["MyProperty"] = "Demo Value";
[YourNamespace].Properties.Settings.Default.Save();
And if you have the need for binary serialization you can use code like this:
(serialized object and object of inheritance must be marked as serializable)
/// <summary>
/// Serializes object to file
/// </summary>
/// <param name="data"></param>
/// <param name="FilePath"></param>
public static void SerializeMyObject(object data, string FilePath)
{
System.IO.Stream stream = null;
try
{
stream = System.IO.File.Open(FilePath, System.IO.FileMode.Create);
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bformatter =
new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
bformatter.Serialize(stream, data);
stream.Close();
stream.Dispose();
}
catch (Exception ex)
{
try
{
stream.Close();
stream.Dispose();
}
catch (Exception)
{
}
throw new Exception(ex.Message);
}
}

Related

Log user input in a c# console application as well as console out

I am currently trying to figure out, what´s the best way to log the user input as well as the output generated by the console.
My current approach is using :
class ConsoleCopy : IDisposable
{
FileStream fileStream;
StreamWriter fileWriter;
TextWriter doubleWriter;
TextWriter oldOut;
class DoubleWriter : TextWriter
{
TextWriter one;
TextWriter two;
public DoubleWriter(TextWriter one, TextWriter two)
{
this.one = one;
this.two = two;
}
public override Encoding Encoding
{
get { return one.Encoding; }
}
public override void Flush()
{
one.Flush();
two.Flush();
}
public override void Write(char value)
{
one.Write(value);
two.Write(value);
}
}
public ConsoleCopy(string path)
{
oldOut = Console.Out;
try
{
fileStream = File.Create(path);
fileWriter = new StreamWriter(fileStream);
fileWriter.AutoFlush = true;
doubleWriter = new DoubleWriter(fileWriter, oldOut);
}
catch (Exception e)
{
Console.WriteLine("Cannot open file for writing");
Console.WriteLine(e.Message);
return;
}
Console.SetOut(doubleWriter);
}
public void Dispose()
{
Console.SetOut(oldOut);
if (fileWriter != null)
{
fileWriter.Flush();
fileWriter.Close();
fileWriter = null;
}
if (fileStream != null)
{
fileStream.Close();
fileStream = null;
}
}
}
and
using (var cc = new ConsoleCopy(log))
{
//some code
Conole.WriteLine(string);
Console.WriteLine(string2);
string input = Console.ReadLine();
}
This approach is working fine for the console output, but I still can not figure out, how to add the user input.
I am redirecting the console output to the file while also being able to see it in the console. That is what I want to achieve with the uesr input aswell.
Thanks a lot!
The same way, actually.
Note that this class only implements ReadLine() for now:
class LoggingReader : TextReader
{
TextReader old;
TextWriter log;
public LoggingReader(TextReader old, TextWriter log)
{
this.old = old;
this.log = log;
}
public override string ReadLine()
{
string input = old.ReadLine();
log.Write("> {0}\r\n", input);
return input;
}
}
These are added to ConsoleCopy as members:
TextReader oldIn;
TextReader loggingReader;
Here is the new ConsoleCopy constructor:
public ConsoleCopy(string path)
{
oldOut = Console.Out;
oldIn = Console.In; // ADDED
try
{
fileStream = File.Create(path);
fileWriter = new StreamWriter(fileStream);
fileWriter.AutoFlush = true;
doubleWriter = new DoubleWriter(fileWriter, oldOut);
loggingReader = new LoggingReader(oldIn, fileWriter); // ADDED
}
catch (Exception e)
{
Console.WriteLine("Cannot open file for writing");
Console.WriteLine(e.Message);
return;
}
Console.SetOut(doubleWriter);
Console.SetIn(loggingReader); // ADDED
}
The log file contents:
This is output 1
This is output 2
> Test
Test command received
Enter to exit
>

Contructor is inaccessible due to its protection level

my error is:
Error 1 'aCI.CheckTexture.CheckTexture()' is inaccessible due to its
protection level
and i use this code to check some files MD5/Hash :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace aCI
{
class CheckTexture
{
Thread Search;
protected CheckTexture()
{
Search = new Thread(Scan);
Search.Start();
}
protected void Scan()
{
if (GetMD5Hash("1.rar") != "9647997C556C5A37A63EFAFBCA4A40D0"
|| GetMD5Hash("2.rar") != "6626959A9099B4C6F5C755E0D2E57EF8"
|| GetMD5Hash("3.rar") != "4D6611A825F81024E0153E2753B8A27E")
{
System.Windows.Forms.MessageBox.Show(
"Sorry come back and restor your orginal files.",
"Error",
System.Windows.Forms.MessageBoxButtons.OK,
System.Windows.Forms.MessageBoxIcon.Error);
return;
}
}
#region Hash Calculator
private static byte[] ConvertStringToByteArray(string data)
{
return (new System.Text.UnicodeEncoding()).GetBytes(data);
}
private static System.IO.FileStream GetFileStream(string pathName)
{
return (new System.IO.FileStream(pathName, System.IO.FileMode.Open,
System.IO.FileAccess.Read, System.IO.FileShare.ReadWrite));
}
public static string GetSHA1Hash(string pathName)
{
string strResult = "";
string strHashData = "";
byte[] arrbytHashValue;
System.IO.FileStream oFileStream = null;
System.Security.Cryptography.SHA1CryptoServiceProvider oSHA1Hasher =
new System.Security.Cryptography.SHA1CryptoServiceProvider();
try
{
oFileStream = GetFileStream(pathName);
arrbytHashValue = oSHA1Hasher.ComputeHash(oFileStream);
oFileStream.Close();
strHashData = System.BitConverter.ToString(arrbytHashValue);
strHashData = strHashData.Replace("-", "");
strResult = strHashData;
}
catch (System.Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message, "Error!",
System.Windows.Forms.MessageBoxButtons.OK,
System.Windows.Forms.MessageBoxIcon.Error,
System.Windows.Forms.MessageBoxDefaultButton.Button1);
}
return (strResult);
}
public static string GetMD5Hash(string pathName)
{
string strResult = "";
string strHashData = "";
byte[] arrbytHashValue;
System.IO.FileStream oFileStream = null;
System.Security.Cryptography.MD5CryptoServiceProvider oMD5Hasher =
new System.Security.Cryptography.MD5CryptoServiceProvider();
try
{
oFileStream = GetFileStream(pathName);
arrbytHashValue = oMD5Hasher.ComputeHash(oFileStream);
oFileStream.Close();
strHashData = System.BitConverter.ToString(arrbytHashValue);
strHashData = strHashData.Replace("-", "");
strResult = strHashData;
}
catch (System.Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message, "Error!",
System.Windows.Forms.MessageBoxButtons.OK,
System.Windows.Forms.MessageBoxIcon.Error,
System.Windows.Forms.MessageBoxDefaultButton.Button1);
}
return (strResult);
}
#endregion
}
}
Then i try Using class CheckTexture from the above code in here:
private void BtnMpLanClick(object sender, RoutedEventArgs e)
{
if (!File.Exists("chrome.exe"))
{
MessageBox.Show("Cannot find chrome.exe");
return;
}
else
{
//Process.Start("chrome.exe");
this.StartTheProcess("chrome.exe", "");
Thread.Sleep(10);
try
{
// I have error on this line:
CheckTexture Scan = new CheckTexture();
}
catch (Exception)
{ }
}
}
but I have that error on this line:
CheckTexture Scan = new CheckTexture();
SO pleas if possible someone tel me what is my mistake.
Thank you for help
The class isn't public. Change it to:
public class CheckTexture
{
Thread Search;
public CheckTexture()
{
Search = new Thread(Scan);
Search.Start();
}
In C#, default access modifier of classes is internal.
So your CheckTexture class is internal. Change it to public like;
public class CheckTexture
{
...
}
From Access Modifiers (C# Programming Guide)
Classes and structs that are declared directly within a namespace (in
other words, that are not nested within other classes or structs) can
be either public or internal. Internal is the default if no access
modifier is specified.
But this doesn't enough. Because when you write;
CheckTexture Scan = new CheckTexture();
This calls parameterless constructor of CheckTexture class which its access modifier is protected. Make it public also.
public CheckTexture()
{
Search = new Thread(Scan);
Search.Start();
}
by default the class in C# is internal. Mark it public. Based on #Caramiriel comment, the constructor also needs to be marked public

"Unable to cast object of type 'System.String' to type 'Payroll.EIR'"

Alright, I have a class "EIR" which is a List based from its base class "ExpenseReport" as such:
using System;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.IO;
using System.Linq;
using System.Text;
namespace Payroll
{
[Serializable]
public class EIR : List<ExpenseItem>
{
public void WriteToFile(string filename)
{
try
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream stream = new FileStream("D:\\myExpensesUpdated.bin", FileMode.Create, FileAccess.Write, FileShare.None);
formatter.Serialize(stream, filename);
stream.Close();
}
catch (Exception ex)
{
Console.WriteLine("Unable to serialize Expenses: {0}", ex.Message);
}
}
public static EIR ReadFromFile(string filename)
{
EIR iRost = new EIR();
try
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream stream = new FileStream("D:\\myExpensesUpdated.bin", FileMode.Open, FileAccess.Read, FileShare.Read);
iRost = (EIR)formatter.Deserialize(stream);
}
catch (Exception ex)
{
Console.WriteLine("Unable to deserialize Expenses: {0}", ex.Message);
}
return iRost;
}
}
}
}
This ReadFromFile part is where I'm having a problem:
In the main program, this portion tries to call ReadFromFile and display newly updated items but I get the error "Unable to cast object of type 'System.String' to type 'Payroll.EIR'".
try
{
EIR expensesUpdated = EIR.ReadFromFile("D:\\myExpensesUpdated.bin");
foreach (var e in expensesUpdated) Console.WriteLine("Updated: {0}", e.ToString());
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
How do I get the iRost to cast to the Payroll.EIR which is a class? Is there some way to convert a serialized string to a class?
Your problem is already in WriteToFile function where you are actually serializing the filename instead of the class. I didn't try it but this should work:
public void WriteToFile(string filename)
{
try
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream stream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None); // filename parameter instead of fixed path
formatter.Serialize(stream, this); // class instance instead of filename parameter
stream.Close();
}
catch (Exception ex)
{
Console.WriteLine("Unable to serialize Expenses: {0}", ex.Message);
}
}
public static EIR ReadFromFile(string filename)
{
EIR iRost = new EIR();
try
{
BinaryFormatter formatter = new BinaryFormatter();
FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read); // filename parameter instead of fixed path
iRost = (EIR)formatter.Deserialize(stream);
}
catch (Exception ex)
{
Console.WriteLine("Unable to deserialize Expenses: {0}", ex.Message);
}
return iRost;
}
Are you sure it's a good idea to silently catch all exceptions and just write a message to console?

Using autogenerated proxy class from XSD (.Net C# 4.0)

I've used xsd.exe to generate a proxy class called "FacturaE".
I can instantiate this class, fill it information, and save to XML with XmlSerializer.
But, given a XML file, well formatted, how can I read it into a "FacturaE"?
Thanks
As a replacement for xsd.exe, Xsd2Code is a much more fully featured class generator. It can add methods to the generated classes to both serialize, and deserialize from Xml.
Following is an example of the serialize/deserialize methods generated by Xsd2Code:
/// <summary>
/// Serializes current EntityBase object into an XML document
/// </summary>
// <returns>string XML value</returns>
public virtual string Serialize() {
System.IO.StreamReader streamReader = null;
System.IO.MemoryStream memoryStream = null;
try {
memoryStream = new System.IO.MemoryStream();
Serializer.Serialize(memoryStream, this);
memoryStream.Seek(0, System.IO.SeekOrigin.Begin);
streamReader = new System.IO.StreamReader(memoryStream);
return streamReader.ReadToEnd();
}
finally {
if (streamReader != null) {
streamReader.Dispose();
}
if (memoryStream != null) {
memoryStream.Dispose();
}
}
}
/// <summary>
/// Deserializes workflow markup into an EntityBase object
/// </summary>
// <param name="xml">string workflow markup to deserialize</param>
// <param name="obj">Output EntityBase object</param>
// <param name="exception">output Exception value if deserialize failed</param>
// <returns>true if this XmlSerializer can deserialize the object; otherwise, false</returns>
public static bool Deserialize(string xml, out T obj, out System.Exception exception) {
exception = null;
obj = default(T);
try {
obj = Deserialize(xml);
return true;
}
catch (System.Exception ex) {
exception = ex;
return false;
}
}
public static bool Deserialize(string xml, out T obj) {
System.Exception exception = null;
return Deserialize(xml, out obj, out exception);
}
public static T Deserialize(string xml) {
System.IO.StringReader stringReader = null;
try {
stringReader = new System.IO.StringReader(xml);
return ((T)(Serializer.Deserialize(System.Xml.XmlReader.Create(stringReader))));
}
finally {
if (stringReader != null) {
stringReader.Dispose();
}
}
}

Stuck on Serialization in C#

I have a class that handles serialization in C#, called Serializer. It's implementation is below:
public class Serializer
{
public void SerializeRulesManager(string filename, RulesManager rulesManager)
{
Stream stream = File.Open(filename, FileMode.Create);
try
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize(stream, rulesManager);
}
finally
{
stream.Close();
}
}
public RulesManager DeserializeRulesManager(string filename)
{
RulesManager rulesManager = null;
Stream stream = File.Open(filename, FileMode.Open);
try
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
rulesManager = (RulesManager)binaryFormatter.Deserialize(stream);
}
finally
{
stream.Close();
}
return rulesManager;
}
}
Pretty straightforward stuff, and it works just fine with all of my unit tests. The RulesManager is correctly serialized and deserialized so I know the graph is good.
The trouble comes with the following code:
public void Save(string filename)
{
Cursor.Current = Cursors.WaitCursor;
try
{
_serializer.SerializeRulesManager(filename, _rulesManager);
}
catch (System.Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
Cursor.Current = Cursors.Default;
}
}
That function is part of the Manager class. The Manager class is instantiated on the MainForm. The MainForm uses a SaveFileDialog to prompt the user for the filename and location they want to save to and then makes the following call:
saveFileDialog.InitialDirectory = Path.GetDirectoryName(Application.ExecutablePath);
if (saveFileDialog.ShowDialog(this) == DialogResult.OK)
{
_manager.Save(saveFileDialog.FileName);
}
Thus calling the function above. When it does so, I get the following exception in Serialize.SerializeRulesManager at the binaryFormatter.Serialize(stream, rulesManager) line:
Type 'TestHarness.MainForm' in Assembly 'TestHarness, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
Why would MainForm need to be marked as Serializable? Just for kicks, I put the Serializable attribute on MainForm and it just moved the exception up one level to say that Windows.Form was not marked as Serializable. What gives?
RulesManager probably has a reference to MainForm. If so, mark it as not serialized with the
NonSerializedAttrbibute

Categories

Resources