Whats the best method to test the serialization? - c#

using System;
using System.Xml.Serialization;
using System.IO;
namespace Mailer {
public class ClientConfiguration {
public virtual bool Save(string fileName) {
XmlSerializer serializer = new XmlSerializer(typeof(ClientConfiguration));
using (StreamWriter writer = new StreamWriter(fileName)) {
serializer.Serialize(writer, this);
}
return true;
}
}
}
In the above code I would like to stub/mock the serializer.Serialize method to ensure that the method is called. I've tried so many way with moq and NMock but failed.
Please help me in stub/mocking the calls to the serializer.

Unless you use Typemock Isolator or Moles, you can't replace anything which is internally created with the new keyword.
You'll need to first extract an interface from the XmlSerializer and then inject that into the class.
As an example, you might introduce this interface:
public interface IXmlSerializer
{
public void Serialize(Stream stream, object o);
}
Inject that into your Mailer class like this:
public class ClientConfiguration
{
private readonly IXmlSerializer serializer;
public ClientConfiguration(IXmlSerializer serializer)
{
if (serializer == null)
{
throw new ArgumentNullException("serializer");
}
this.serializer = serializer;
}
public virtual bool Save(string fileName)
{
using (StreamWriter writer = new StreamWriter(fileName))
{
this.serializer.Serialize(writer, this);
}
return true;
}
}
Now you can inject the mock into the class:
var mock = new Mock<IXmlSerializer>();
var sut = new ClientConfiguration(mock.Object);
The above example uses Moq.

Related

Using method from Class to change class

I wanted to create a class and use a method from the initialized class to change the property values of the calling instance. Somehow I have a knot in my brain and there seems to be a basic thinking error of mine. Maybe someone can help me figure it out.
Class Program
{
...
private void Initialize()
{
Zoo myZoo = new Zoo();
myZoo.Load();
Console.WriteLine(myZoo.ZooName);
}
}
and the Zoo-Class:
public class Zoo
{
public string ZooName { get; set; }
...
internal void Load()
{
Zoo myZoo = this;
using (StreamReader reader = File.OpenText(#"C:\Areas.json"))
{
JsonSerializer serializer = new JsonSerializer();
myZoo = (Zoo) serializer.Deserialize(reader, typeof(Zoo));
}
}
}
The JSON part works fine, but as soon as the Load()-method comes to an end the myZoo/this is set to NULL. Is there any possibility to use 'this' to modify the property values of the calling class instance?
You probably want to make a factory method on your class instead. This function will return a new instance of Zoo with the data from your json file.
Like this:
public class Zoo
{
public string ZooName { get; set; }
...
public static Zoo Init()
{
using (StreamReader reader = File.OpenText(#"C:\Areas.json"))
{
JsonSerializer serializer = new JsonSerializer();
var myZoo = (Zoo) serializer.Deserialize(reader, typeof(Zoo));
return myZoo;
}
}
}
In your Initialize function you can now create an instance like this:
private void Initialize()
{
var myZoo = Zoo.Init();
Console.WriteLine(myZoo.ZooName);
}
other way out.you can use ref keyword for the same.
Class Program
{
...
private void Initialize()
{
Zoo myZoo = new Zoo();
myZoo.Load(ref myZoo);
Console.WriteLine(myZoo.ZooName);
}
}
public class Zoo
{
public string ZooName { get; set; }
...
internal void Load(ref Zoo myZoo)
{
using (StreamReader reader = File.OpenText(#"C:\Areas.json"))
{
JsonSerializer serializer = new JsonSerializer();
myZoo = (Zoo) serializer.Deserialize(reader, typeof(Zoo));
}
}
}
You cannot set the this pointer. There also is no assignment operator in C# to overload.
You could copy all properties from your loaded zoo object into the this object.
A more common approach is to have a static factory method to do this for you:
public class Zoo
{
public string ZooName { get; set; }
...
public static Zoo Load(string file)
{
using (StreamReader reader = File.OpenText(file))
{
JsonSerializer serializer = new JsonSerializer();
return (Zoo) serializer.Deserialize(reader, typeof(Zoo));
}
}
}
Later call it like this:
Zoo z = Zoo.Load(#"C:\Areas.json");

XML Deserialization inside class

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.

.NET Serializable entity

I need to make all my entities serializable. So I was thinking in a BaseEntity with a Backup and a Restore method. But in the restore I can't override the object with the saved one because this is read-only.
Any solution or some other way to get the serializable entities?
My code:
internal class BaseEntity
{
private MemoryStream ms = new MemoryStream();
private BinaryFormatter bf = new BinaryFormatter();
public void Backup()
{
bf.Serialize(ms, this);
}
public void Restore()
{
this = (BaseEntity)bf.Deserialize(ms);
}
}
The more common pattern is to not make it the responsibility of your objects to serialize/deserialize themselves; rather, use an external serializer:
var serializer = new DataContractJsonSerializer(typeof(YourClass));
var stream = ...;
YourClass yourObj = ...;
serializer.WriteObject(stream, yourObj);
var restoredObj = serializer.ReadObject(stream);
Edit: One way serialization can work is to use the System.Runtime.Serialization.Formatters.Binary.BinaryFormatter (or other implementation of IFormatter). To serialize an object you pass the object and a stream. To Deserialize the object, you pass a stream (positioned at the begining of your serialized data), and it returns the serialized object and all its depenedencies.
public static class EntityBackupServices
{
public static MemoryStream Backup (BaseEntity entity)
{
var ms = new MemoryStream();
Serialize (ms, entity);
ms.Position = 0;
return ms;
}
public static void Serialize (Stream stream, BaseEntity entity)
{
var binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize (stream, entity);
}
public static BaseEntity Restore (Stream stream)
{
var binaryFormatter = new BinaryFormatter();
var entity = (BaseEntity) binaryFormatter.Deserialize (stream);
return entity;
}
}
One thing a formatter don't do (though the FormatterServices class makes it possible) is modify existing objects. So you probably don't want to have an instance method called Deserialize. You can't really do this: new LionEntity().Deserialize () where it replaces the fields of an existing instance.
Note: You'll need to put Serializable over all your types. Any fields that can't be serialized (because it's either not a struct, or it's not marked as [Serializable] will need to be marked with NonSerialized.
// A test object that needs to be serialized.
[Serializable()]
public class BaseEntity
{
public int member1;
public string member2;
public string member3;
public double member4;
// A field that is not serialized.
[NonSerialized()] public MyRuntimeType memberThatIsNotSerializable;
public TestSimpleObject()
{
member1 = 11;
member2 = "hello";
member3 = "hello";
member4 = 3.14159265;
memberThatIsNotSerializable = new Form ();
}
public MemoryStream Backup ()
{
return EntityBackupServices.Backup (this);
}
}
Edit:
The way I've mentioned is a rather standard and accepted way. If you want to venture into hackdom, you can deserialize the object the way I've mentioned, then use reflection to set each field on your existing object to the value of the deserialized object.
public class BaseEntity
{
void Restore(Stream stream)
{
object deserialized = EntityBackupServices.RestoreDeserialize(stream);//As listed above
if (deserialized.GetType () != this.GetType ())
throw new Exception();
foreach (FieldInfo fi in GetType().GetFields())
{
fi.SetValue(this, fi.GetValue (deserialized));
}
}
}
public IEntidadBase Restore()
{
return (IEntidadBase)bf.Deserialize(ms);
}
#jacklondon how would you do EntitySerializer methods?
You can do serialization process with http://www.servicestack.net/ StackService.Text module for clean entities. You don't need any attribute (serializable/datacontract) in ms way.
public class EntityFoo
{
public string Bar { get; set; }
public EntityFoo (string bar)
{
Bar = bar;
}
}
public class EntityDumper //and the EntitySerializer
{
public static string Dump<T> (T entity)
{
return new TypeSerializer<T> ().SerializeToString (entity);
}
public static T LoadBack<T> (string dump)
{
return new TypeSerializer<T> ().DeserializeFromString (dump);
}
}
public class dump_usage
{
public void start ()
{
string dump = EntityDumper.Dump (new EntityFoo ("Space"));
EntityFoo loaded = EntityDumper.LoadBack<EntityFoo> (dump);
Debug.Assert (loaded.Bar == "Space");
}
}
I don't necessarily recommend this, but here is one pattern for an object that can persist and restore its own state using serialization that creates new instances:
public sealed class MyClass
{
private Data _data = new Data();
//Properties go here (access the public fields on _data)
public void Backup()
{
//Serialize Data
}
public void Restore()
{
//Deserialize Data and set new instance
}
private sealed class Data
{
//Public fields go here (they're private externally [because Data is private], but public to MyClass.)
}
}
Note that this only works if your serializer supports non-public classes. Worst-case, you have to make the nested class public, which is ugly, but doesn't hurt encapsulation (since the instance is private).

Exception converting surrogate type created in ISerializable.GetObjectData when object is field in a Serializable class

I have a value object class (UserData) that is marked as Serializable and contains another class (StringType) that is marked as Serializable and implements ISerializable so that it can return singleton instances. The StringType class serializes and deserializes fine on it's own, but when it is used as a property on another object that is marked as Serializable, I get an exception truing to convert from the helper class deserialize into a singleton.
Object of type 'Spring2.Core.Test.Serialization.StringType_DEFAULT' cannot be converted to type 'Spring2.Core.Test.Serialization.StringType'.
I am using a BinaryFormatter and need to use that so that I can store this UserData object in an ASP.NET session using SQL server storage.
Here is a very stripped down version of the StringType class as well as some tests that show that serialization/deserialization work for StringType by itself, but not when as a field on UserData.
StringType:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
using System.Security.Permissions;
namespace Spring2.Core.Test.Serialization {
public enum TypeState : short {
DEFAULT,
VALID,
UNSET
}
[Serializable]
public struct StringType : ISerializable {
private string myValue;
private TypeState myState;
public static readonly StringType DEFAULT = new StringType(TypeState.DEFAULT);
public static readonly StringType UNSET = new StringType(TypeState.UNSET);
private StringType(TypeState state) {
myState = state;
myValue = "";
}
public StringType(String s) {
myValue = s;
myState = TypeState.VALID;
}
public bool IsValid {
get { return myState == TypeState.VALID; }
}
public bool IsDefault {
get { return myState == TypeState.DEFAULT; }
}
public bool IsUnset {
get { return myState == TypeState.UNSET; }
}
public override string ToString() {
return IsValid ? this.myValue : myState.ToString();
}
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
StringType(SerializationInfo info, StreamingContext context) {
myValue = (System.String)info.GetValue("myValue", typeof(System.String));
myState = (TypeState)info.GetValue("myState", typeof(TypeState));
}
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {
if (this.Equals(DEFAULT)) {
info.SetType(typeof(StringType_DEFAULT));
} else if (this.Equals(UNSET)) {
info.SetType(typeof(StringType_UNSET));
} else {
info.SetType(typeof(StringType));
info.AddValue("myValue", myValue);
info.AddValue("myState", myState);
}
}
}
[Serializable]
public class StringType_DEFAULT : IObjectReference {
public object GetRealObject(StreamingContext context) {
return StringType.DEFAULT;
}
}
[Serializable]
public class StringType_UNSET : IObjectReference {
public object GetRealObject(StreamingContext context) {
return StringType.UNSET;
}
}
}
Tests:
using System;
using NUnit.Framework;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace Spring2.Core.Test.Serialization {
/// <summary>
/// Tests for BooleanType
/// </summary>
[TestFixture]
public class DataTypeSerializationTest {
[Test]
public void ShouldBinarySerializeStringTypeWithValue() {
BinaryFormatter binaryFmt = new BinaryFormatter();
StringType s = new StringType("foo");
FileStream fs = new FileStream("foo.dat", FileMode.OpenOrCreate);
binaryFmt.Serialize(fs, s);
fs.Close();
Console.WriteLine("Original value: {0}", s.ToString());
// Deserialize.
fs = new FileStream("foo.dat", FileMode.OpenOrCreate);
StringType s2 = (StringType)binaryFmt.Deserialize(fs);
Console.WriteLine("New value: {0}", s2.ToString());
fs.Close();
Assert.AreEqual(s.ToString(), s2.ToString());
}
[Test]
public void ShouldBinarySerializeStringTypeUnset() {
BinaryFormatter binaryFmt = new BinaryFormatter();
StringType s = StringType.UNSET;
FileStream fs = new FileStream("foo.dat", FileMode.OpenOrCreate);
binaryFmt.Serialize(fs, s);
fs.Close();
Console.WriteLine("Original value is UNSET: {0}", s.IsUnset);
// Deserialize.
fs = new FileStream("foo.dat", FileMode.OpenOrCreate);
StringType s2 = (StringType)binaryFmt.Deserialize(fs);
Console.WriteLine("new value is UNSET: {0}", s2.IsUnset);
fs.Close();
Assert.IsTrue(s2.IsUnset);
}
[Test]
public void ShouldDeserializeDataObject() {
BinaryFormatter binaryFmt = new BinaryFormatter();
UserData u = new UserData();
FileStream fs = new FileStream("foo.dat", FileMode.OpenOrCreate);
binaryFmt.Serialize(fs, u);
fs.Close();
Console.WriteLine("Original value is UNSET: {0}", u.Name.IsUnset);
// Deserialize.
fs = new FileStream("foo.dat", FileMode.OpenOrCreate);
Object o = binaryFmt.Deserialize(fs);
UserData u2 = (UserData)o;
Console.WriteLine("new value is UNSET: {0}", u2.Name.IsUnset);
fs.Close();
Assert.IsTrue(Object.Equals(u, u2));
}
}
[Serializable]
public class UserData {
private StringType name = StringType.DEFAULT;
public StringType Name {
get { return name; }
set { name = value; }
}
}
}
Any help would be MUCH appreciated!
Cort
Cort you should change your IObjectReference implementations to return a struct. The third unit test will fail, but it fails on the assertion of the Objects being equal, rather than throwing the type mismatch exception.
[Serializable]
public struct StringType_DEFAULT : IObjectReference {
public object GetRealObject(StreamingContext context) {
return StringType.DEFAULT;
}
}
[Serializable]
public struct StringType_UNSET : IObjectReference {
public object GetRealObject(StreamingContext context) {
return StringType.UNSET;
}
}
You need to change StringType to be a class instead of a struct.
Since your DEFAULT and UNSET StringTypes are static readonly and constructed with the class, you shouldn't need to serialize them at all. Attribute them as [field:nonserialized].
Additionally, unless you have specific logic that needs to happen, you don't need to implement ISerializable for this class. Attributing it as [Serializable] should be enough.

Generics + XML Serialization + Custom Objects

I'm trying out Generics and I had this (not so) great idea of creating an XMLSerializer class. The code I pieced together is below:
public class Persist<T>
{
private string _path;
public Persist(string path) {
this._path = path;
}
public void save(T objectToSave)
{
XmlSerializer s = new XmlSerializer(typeof(T));
TextWriter w = new StreamWriter(this._path);
try { s.Serialize(w, objectToSave); }
catch (InvalidDataException e) { throw e; }
w.Close(); w.Dispose();
}
public T load()
{
XmlSerializer s = new XmlSerializer(typeof(T));
TextReader r = new StreamReader(this._path);
T obj;
try { obj = (T)s.Deserialize(r); }
catch (InvalidDataException e) { throw e; }
r.Close(); r.Dispose();
return obj;
}
}
Here's the problem: It works fine on Persist<List<string>> or Persist<List<int>> but not on Persist<List<userObject>> or any other custom (but serializable) objects. userObject itself is just a class with two {get;set;} properties, which I have serialized before.
I'm not sure if the problems on my Persist class (generics), XML Serialization code, or somewhere else :( Help is very much appreciated~
Edit:
code for userObject
public class userObject
{
public userObject(string id, string name)
{
this.id = id;
this.name = name;
}
public string id { get;private set; }
public string name { get;set; }
}
Looks to me like your code should just work - even though it does have a few flaws.
EDIT: Your userObject class isn't serializable. Xml serialization only works on types with a public, parameterless constructor - the current class won't work. Also, you should really rewrite your code to avoid explicit calls to .Close() or .Dispose() and instead prefer using where possible - as is, you might get random file locking if at any point during serialization an error occurs and your method terminates by exception - and thus doesn't call .Dispose().
Personally, I tend to use a just-for-serialization object hierarchy that's just a container for data stored in xml and avoids any behavior - particularly side effects. Then you can use a handly little base class that makes this simple.
What I use in my projects is the following:
public class XmlSerializableBase<T> where T : XmlSerializableBase<T>
{
static XmlSerializer serializer = new XmlSerializer(typeof(T));
public static T Deserialize(XmlReader from) { return (T)serializer.Deserialize(from); }
public void SerializeTo(Stream s) { serializer.Serialize(s, this); }
public void SerializeTo(TextWriter w) { serializer.Serialize(w, this); }
public void SerializeTo(XmlWriter xw) { serializer.Serialize(xw, this); }
}
...which caches the serializer in a static object, and simplifies usage (no generic type-paramenters needed at call-locations.
Real-life classes using it:
public class ArtistTopTracks {
public string name;
public string mbid;//always empty
public long reach;
public string url;
}
[XmlRoot("mostknowntracks")]
public class ApiArtistTopTracks : XmlSerializableBase<ApiArtistTopTracks> {
[XmlAttribute]
public string artist;
[XmlElement("track")]
public ArtistTopTracks[] track;
}
Sample serialization calls:
using (var xmlReader = XmlReader.Create([...]))
return ApiArtistTopTracks.Deserialize(xmlReader);
//[...]
ApiArtistTopTracks toptracks = [...];
toptracks.SerializeTo(Console.Out);
There can be a number of reasons why your code fails: This text is particularly helpful when having issues: Troubleshooting Common Problems with the XmlSerializer . Maybe you have some type hierarchy in your user objects and the serializer does not know about it?

Categories

Resources