I do not know if this is even possible but let's suppose I have a class:
[Serializable]
public class Test
{
//Properties and functions would go here.
public void SaveClass(string FilePath)
{
System.IO.Stream stream = System.IO.File.Create(FilePath);
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
binaryFormatter.Serialize(stream, this);
stream.Close();
}
public void LoadClass(string FilePath)
{
System.IO.Stream stream = System.IO.File.OpenRead(FilePath);
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
this = binaryFormatter.Deserialize(stream); //It returns an error saying that 'this' is readonly.
stream.Close();
}
}
Now I want to be able to Save and Load the class. The SaveClass is working fine, but the LoadClass returns an error, because I can not assign anything to this. Is there a way that I could load the class from a file, or is this impossible.
Make LoadClass static, something like:
public static Test LoadClass(string FilePath)
{
System.IO.Stream stream = System.IO.File.OpenRead(FilePath);
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
var newTest = (Test)binaryFormatter.Deserialize(stream);
stream.Close();
return newTest;
}
Related
I have my class, example:
[Serializable]
public class ServerItem
{
public string Id { get; }
public string Name => this.info.Name;
public bool IsOptimal { get; set; }
public string Region => this.info.Region;
public string City => this.info.Description;
public Point? Location { get; }
}
I use my own method for serialize this class
public static byte[] Serialize(object obj)
{
try
{
byte[] bytes;
IFormatter formatter = new BinaryFormatter();
using (MemoryStream stream = new MemoryStream())
{
formatter.Serialize(stream, obj);
bytes = stream.ToArray();
}
return bytes;
}
catch
{
return null;
}
}
and I get the exception. That point cannot be serialized, because it hasn't attribute [Serializable]
But I can't set this attribute, because it's not my own class.
What can I do at this situation ?
I know this isn't helpful for you current problem, but Microsoft recommends strongly to don't use BinaryFormatter anymore.
The BinaryFormatter type is dangerous and is not recommended for data
processing. Applications should stop using BinaryFormatter as soon as
possible, even if they believe the data they're processing to be
trustworthy. BinaryFormatter is insecure and can't be made secure.
Source: https://learn.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-security-guide
On this page are also further resources for alternatives.
I tried XML serialization the first time. The following code works as expected, but I don't like to use this "copyFrom" method.
Is there a better way that keeps the save and load methods inside the class itself?
namespace Test
{
[Serializable]
public class Settings
{
public struct Connection
{
[XmlAttribute ("user")]
public string sUser;
[XmlAttribute ("domain")]
public string sDomain;
}
public Connection connection;
public Settings ()
{
connection.sUser = "";
connection.sDomain = "";
}
internal void loadFromFile ()
{
if (File.Exists (Constants.STORAGE_SETTINGS_FILE))
{
using (FileStream filestream = new FileStream (Constants.STORAGE_SETTINGS_FILE, FileMode.Open, FileAccess.Read, FileShare.Read))
{
copyFrom ((Settings)new XmlSerializer (typeof (Settings)).Deserialize (filestream));
}
}
}
internal void saveToFile ()
{
using (StreamWriter streamwriter = new StreamWriter (Constants.STORAGE_SETTINGS_FILE))
{
new XmlSerializer (typeof (Settings)).Serialize (streamwriter, this);
}
}
internal void copyFrom (Settings settings)
{
connection.sUser = settings.connection.sUser;
connection.sDomain = settings.connection.sDomain;
}
}
}
You can remove copyFrom method.
In the loadFromFile method, you can write
connection = ((Settings)new XmlSerializer(typeof(Settings)).Deserialize(filestream)).connection;
Also note that the Serializable attribute not needed for XML serialization. Remove it.
I'm using Moq to mock HttpWebResponse for unit testing. I created a mock class that inherits from the class I'm trying to test and I'm overriding the method that returns the HttpWebResponse. I want to write a JSON string to the response stream from the unit test but I get an ArgumentException when trying to read the stream saying "Stream was not readable".
Here is what I have:
public class ParentClass
{
private string ProcessResponse(HttpWebResponse response)
{
string json = String.Empty;
using (var streamReader = new StreamReader(response.GetResponseStream())) //exception here
{
json = streamReader.ReadToEnd();
}
return json;
}
//other stuff
}
public class MockClass : ParentClass
{
public Stream responseStream = new MemoryStream();
public void WriteJson(string json)
{
using(var writer = new StreamWriter(responseStream))
{
writer.Write(json);
}
}
protected override HttpWebResponse GetResponse(HttpWebRequest request)
{
var response = new Mock<HttpWebResponse>();
response.Setup(r => r.GetResponseStream()).Returns(responseStream);
return response.Object;
}
}
The problem seemed to be with the using statement. Here are the changes I made:
public void WriteJson(string json)
{
var jsonBytes = Encoding.UTF8.GetBytes(json);
responseStream.Write(jsonBytes, 0, jsonBytes.Length);
responseStream.Seek(0, SeekOrigin.Begin);
}
It's safer to use an overload of StreamWriter which leaves the underlying stream open:
public StreamWriter(Stream stream, Encoding encoding, int bufferSize, bool leaveOpen)
I'd like to Deserialize my "DataStore" to get a list of Typs. First i want to make theese in XMl with the XMLSerializer but it seems that he dont like Interfaces, Abstract Class and Typs ... but there is no Workaround so i need to store my Main content in an XML class:
public class InstalledObjects
{
private InstalledObjects()
{
}
static InstalledObjects _instance = new InstalledObjects();
ObservableCollection<AbstrICTSUseObject> _installedObects = new ObservableCollection<AbstrICTSUseObject>();
public static InstalledObjects Instance
{
get { return _instance; }
set { _instance = value; }
}
public ObservableCollection<AbstrICTSUseObject> InstalledObects
{
get { return _installedObects; }
set { _installedObects = value; }
}
public void Saves()
{
List<Type> types = new List<Type>();
foreach (var item in InstalledObects)
{
types.Add( item.GetType() );
}
TypeStore ts = new TypeStore();
ts.Typen = types;
ts.SaveAsBinary("TypeStore.xml");
this.SaveAsXML("LocalDataStore.xml", types.ToArray());
}
public void Load()
{
if (File.Exists("LocalDataStore.xml"))
{
TypeStore ts = new TypeStore();
ts.LoadFromBinary("LocalDataStore.xml");
this.LoadFromXML("LocalDataStore.xml",ts.Typen.ToArray());
}
}
}
And store my Typs in an Simple class:
[Serializable]
public class TypeStore
{
List<Type> _typen = new List<Type>();
public List<Type> Typen
{
get { return _typen; }
set { _typen = value; }
}
}
Ok good think this works as long as i just Save all, and i Think this will also working if there would not the litte problem that the "LoadFromBinary" throw some expetions -.-
public static void SaveAsBinary(this Object A, string FileName)
{
FileStream fs = new FileStream(FileName, FileMode.Create);
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(fs, A);
}
public static void LoadFromBinary(this Object A, string FileName)
{
if (File.Exists(FileName))
{
Stream fs = new FileStream(FileName, FileMode.Open);
BinaryFormatter formatter = new BinaryFormatter();
A = formatter.Deserialize(fs) ;
}
}
The Expeption:
The input stream is not a valid binary format. The starting contents (in bytes) are: 3C-3F-78-6D-6C-20-76-65-72-73-69-6F-6E-3D-22-31-2E ...
Thx for help Venson :-)
Is this as simple as the fact that you're reading from the wrong file?
Note:
ts.SaveAsBinary("TypeStore.xml");
this.SaveAsXML("LocalDataStore.xml", types.ToArray());
Then:
ts.LoadFromBinary("LocalDataStore.xml");
this.LoadFromXML("LocalDataStore.xml", ts.Typen.ToArray());
Should be:
ts.LoadFromBinary("TypeStore.xml");
this.LoadFromXML("LocalDataStore.xml", ts.Typen.ToArray());
however, note that calling it .xml is misleading. Also: watch out for versioning - BinaryFormatter is a real pig for that. Personally, I'd just be manually serializing each type's AssemblyQualifiedName - which can be done in normal xml.
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