Serialize and Deserialize Oracle.DataAccess.OracleException in C# - c#

OracleException has no public constructors nor any way to get a new instance. I tried my XmlSerializerHelper class, but it requires a public parameterless constructor.
I used BinaryFormatter to serialize the OracleException and wrote it to a file.
How can I serialize OracleException in a file, and deserialize too using XmlSerializer -for testing reasons-?.
Reference:
http://geekswithblogs.net/WillSmith/archive/2008/07/25/testing-oracleexception.aspx
PD: Is better SoapFormatter or BinaryFormatter ?
Code
SerializationHelper.Serialize(#"C:\Temp\ExcepcionOracle.bin", ex);
var exOra = SerializationHelper.Deserialize(#"C:\Temp\ExcepcionOracle.bin");
public static void Serialize(string fileName, Object obj)
{
var binaryFormatter = new BinaryFormatter();
var fileStream = new FileStream(fileName, FileMode.Create);
try
{
binaryFormatter.Serialize(fileStream, obj);
}
catch (SerializationException ex)
{
throw new ApplicationException("The object graph could not be serialized", ex);
}
finally
{
fileStream.Close();
}
}
public static object Deserialize(string fileName)
{
var binaryFormatter = new BinaryFormatter();
var fileStream = new FileStream(fileName, FileMode.Open);
try
{
fileStream.Seek(0, SeekOrigin.Begin);
return binaryFormatter.Deserialize(fileStream);
}
catch (SerializationException ex)
{
throw new ApplicationException("Serialization Exception: " + ex.Message);
}
finally
{
fileStream.Close();
}
return null;
}

things like Exception simply aren't very suitable for xml serializers (and XmlSerializer in particular). In addition to the constructor issues (which some serializers can work around, and some can't), you are also likely to get issues with unexpected subclasses and arbitrary data in the collection.
If you are serializing as xml, you should probably just capture the key information you need - maybe the .Message and a few other things. Note also that in a client/server application the client doesn't really need to know much of the particulars of the failure - that should remain at the server. Either it is an exected error (invalid parameters, login issues, quota restrictions, etc), or it is an unexpected error. In the latter case: just say an unexpected error happened. The details would only be useful to a developer, and a developer should already have access to the server's error log.

Related

Deserializing a BinaryFormatter result into another type

We had recently rewritten our system's architecture and ran into a pretty big issue the day we went live.
We save a user's information as they are filling out their forms by serializing the form's model using BinaryFormatter and storing the result in the database:
private byte[] Serialize<T>(T model)
{
try
{
var formatter = new BinaryFormatter();
using (var stream = new MemoryStream())
{
formatter.Serialize(stream, model);
return stream.ToArray();
}
}
catch (System.Exception ex)
{
_log.LogException(ex);
}
return null;
}
When the user needed the information again, we would simply deserialize back into the same type and that worked great:
public T Deserialize<T>(byte[] serializedData)
{
try
{
var formatter = new BinaryFormatter();
using (var stream = new MemoryStream(serializedData))
{
var result = (T)formatter.Deserialize(stream);
return result;
}
}
catch (System.Exception ex)
{
_log.LogException(ex);
return default(T);
}
}
The problem comes in after the architecture rewrite and we had 3 clients that still had legacy form data saved. The updated architecture's form models has the same property names but obviously new namespaces in a new assembly.
As a result the formatter.Deserialize is failing because it's trying to deserialize into an object that is in an assembly that is not in the new architecture.
Is there any possible way I can somehow deserialize into a generic object and then do a deep copy into the new model (or use automapper or something like that)? Or is the BinaryFormatter tightly tied to object and I would need the dll that contained the type definition that was used to do the serialization in order to do the deserialization?

C# generics code-bloat - should I be worried?

I'd like to ask something about generics.
I am trying to keep the code simple, and thus I will be making a single class to handle load/save for a game's savegame files. As each portion of the game has different requirements I'd like to keep this as easily accessible as possible:
public void Load<T>(string path, out T obj)
{
BinaryFormatter bf = new BinaryFormatter();
using (FileStream file = File.Open(Application.persistentDataPath + path, FileMode.Open))
{
obj = (T)bf.Deserialize(file);
}
}
Now I can call this with a simple
TurnData x; s.Load("test.txt", out x);
The alternative would be to make the Load function return the object and then convert it to a TurnData type.
TurnData x = (TurnData)s.Load("test.txt");
I do not know much about C#. I assume that the code inside using(...) { ... } does not get executed if there is an error opening the file for example? If someone can confirm this that would be nice. The example code I have seen did not have any error handling, which seemed weird to me, so I added using?
So in this secondary version where the function returns the object instead of using an out parameter would need more complicated code for error checking and possible return null? It doesn't seem great.
So the real question is ... can I use the next version I have here or are there concerns that I should have due to the use of generics?
There is no generic code bloat for reference types - code is reused. With value types, though, CLR will generate a separate method for each type. See
.NET Generics and Code Bloat.
The using statement has nothing to do with error handling. Using File.Open method you can expect to get the exceptions you will find here. You could avoid the abruptly stop of your program from any such an exception by wrapping your using statement in a try/cath construct like below:
public T Load<T>(string path)
{
T obj = default(T);
var bf = new BinaryFormatter();
try
{
using (var file = File.Open(Application.persistentDataPath + path, FileMode.Open))
{
obj = (T)bf.Deserialize(file);
}
}
catch(Exception exception)
{
// Log the exception
}
return obj;
}
Essentially you attempt to Open the file specified in the path. If that fails you just log the failure and your return null from the function.
Regarding the using statement, it provides
a convenient syntax that ensures the correct use of IDisposable
objects.
as you can read more thoroughly here
As a side note regarding the signature of your method I would make a few comments. Consider the following method body and spot the differences with that we have above.
public T Load<T>(string path, IFormatter formatter)
{
if(path ==null) throw new ArgumentNullException(nameof(path));
if(formatter == null) throw new ArgumentNullException(nameof(formatter));
T obj = default(T);
try
{
using (var file = File.Open(path, FileMode.Open))
{
obj = (T)formatter.Deserialize(file);
}
}
catch(Exception exception)
{
// Log the exception
}
return obj;
}
and
var path = Path.Combine(Application.persistentDataPath, "test.txt");
var binaryFormatter = new BinaryFormatter();
var x = s.Load(path, binaryFormatter);
Making the above changes you make your method more easily to be tested through a unit test and more reliable since you make some precondition checking before the meat and potatoes of your method. What would had happened if you had passed a null path? What would had happened if you had passed a null formatter ? etc...

Are Hashtables Serializable?

I see a pervasive belief (2009 article) throughout the internet that the Hashtable class is not serializable; however, I cannot find any modern documentation that supports this notion.
The belief stems from another ill-documented belief that the IDictionary interface prevents serialization; however, I cannot find anything in MSDN that supports this claim, today.
Further, Hashtable implements ISerializable and contains extension methods that accept serialization information.
So, what's the deal? Is Hashtable serializable? Where is the documentation that supports this notion surrounding IDictionary?
Further Clarification (please read):
The statement that IDictionary is not serializable is supported by plenty of documentation; however, this focuses on the use of XML-based serialization interactions with a class. ISerializable as mentioned both in the comments, below, and through MSDN indicates that a class is serializable. It also means the class the must be responsible for its own serialization.
I think this negates the statement that a Hashtable is not serializable. That is perhaps the genesis of my question.
The pervasive belief is so pervasive because it's true:
var t = new Hashtable();
t.Add("Hi!", "I'm here");
t.Add("Hm", "Yup");
var serializer = new XmlSerializer(typeof(Hashtable));
using (var sw = new StringWriter())
{
serializer.Serialize(sw, t);
Console.WriteLine(sw.ToString());
}
throws
NotSupportedException: The type System.Collections.Hashtable is not supported because it implements IDictionary.
That doesn't mean that it's literally impossible to serialize a hash table. Of course I can just iterate over all the keys and values, write them to a string and then reconstruct the hashtable from that. It's just that I can't use the serialization infrastructure fully.
What's the reasoning here? It's actually quite simple - XmlSerializer is designed to produce good XML, in the spirit of the interchange format XML was designed to be. And XML doesn't have any kind of dictionary or "key-value" mechanism that would fit. So to support hashtable serialization, they'd have to make their own "sub-format" with its own rules. And back when .NET was being designed, this was a huge no-no - XML was an interchange format. Any extension (hah) to the format means you're no longer compatible, no matter how good of an idea you have.
Of course, nowadays, everyone and their grandmother are producing XML data that isn't used for interchange purposes. And it's not entirely a bad thing (after all, .NET config files are also a XML format). But it's also kind of wrong.
In contrast, take something like BinaryFormatter. That's a class where the .NET team designed the whole format, and isn't limited by a standard. And lo and behold - BinaryFormatter can serialize and deserialize a Hashtable just fine.
So the slightly more correct belief would be "Hashtable cannot be serialized to valid standard XML. The XmlSerializer class in particular will throw an error when you attempt to serialize a Hashtable."
Does Hashtable implement ISerializable? Absolutely:
public class Hashtable : IDictionary, ICollection, IEnumerable, ISerializable, IDeserializationCallback, ICloneable
Can we serializae a Hashtable to XML? Let's try it:
var hash = new System.Collections.Hashtable();
hash[7] = "7";
hash[8] = "8";
var serializer = new System.Xml.Serialization.XmlSerializer(typeof(System.Collections.Hashtable));
TextWriter writer = new System.IO.StreamWriter(#"C:\SomeFile.xml");
serializer.Serialize(writer, hash);
Result... Error as you expected
An exception of type 'System.NotSupportedException' occurred in System.Xml.dll but was not handled in user code
Additional information: The type System.Collections.Hashtable is not supported because it implements IDictionary.
So, it would appear that indeed, it's still the case in .Net 4.5+
But lets try one more time with a binary serialization...
var hash = new System.Collections.Hashtable();
hash[7] = "7";
hash[8] = "8";
var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
Stream stream = new FileStream(#"C:\SomeFolder\SomeFile.bin", FileMode.Create, FileAccess.Write, FileShare.None);
formatter.Serialize(stream, hash);
stream.Close();
Result... No Errors thrown... So the issue appears to be related to IDictionary and XmlSerialization, but not all Serialization
If you really need to do this to XML, ManoDestra had a nice link https://blogs.msdn.microsoft.com/adam/2010/09/10/how-to-serialize-a-dictionary-or-hashtable-in-c/
Also, interestingly, XML Serialization mentions that you can't serialize unsigned longs or collections there-of.
Microsoft XML Serialization (MSDN)
Microsoft seems to say that it is certainly possible to do this.
https://msdn.microsoft.com/en-us/library/b85344hz(v=vs.110).aspx
using System;
using System.IO;
using System.Collections;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
public class App
{
[STAThread]
static void Main()
{
Serialize();
Deserialize();
}
static void Serialize()
{
// Create a hashtable of values that will eventually be serialized.
Hashtable addresses = new Hashtable();
addresses.Add("Jeff", "123 Main Street, Redmond, WA 98052");
addresses.Add("Fred", "987 Pine Road, Phila., PA 19116");
addresses.Add("Mary", "PO Box 112233, Palo Alto, CA 94301");
// To serialize the hashtable and its key/value pairs,
// you must first open a stream for writing.
// In this case, use a file stream.
FileStream fs = new FileStream("DataFile.dat", FileMode.Create);
// Construct a BinaryFormatter and use it to serialize the data to the stream.
BinaryFormatter formatter = new BinaryFormatter();
try
{
formatter.Serialize(fs, addresses);
}
catch (SerializationException e)
{
Console.WriteLine("Failed to serialize. Reason: " + e.Message);
throw;
}
finally
{
fs.Close();
}
}
static void Deserialize()
{
// Declare the hashtable reference.
Hashtable addresses = null;
// Open the file containing the data that you want to deserialize.
FileStream fs = new FileStream("DataFile.dat", FileMode.Open);
try
{
BinaryFormatter formatter = new BinaryFormatter();
// Deserialize the hashtable from the file and
// assign the reference to the local variable.
addresses = (Hashtable) formatter.Deserialize(fs);
}
catch (SerializationException e)
{
Console.WriteLine("Failed to deserialize. Reason: " + e.Message);
throw;
}
finally
{
fs.Close();
}
// To prove that the table deserialized correctly,
// display the key/value pairs.
foreach (DictionaryEntry de in addresses)
{
Console.WriteLine("{0} lives at {1}.", de.Key, de.Value);
}
}
}

C#_WCF Xml Serialization

I am serializing object through XMLSerializer ,but every time i invoke the method old data is getting replaced with the new data,i want to append the object every time i invoke not rewrite ,Below is the code which i have written please help me
XmlSerializer mySerializer = new XmlSerializer(typeof(Employee));
StreamWriter stream = new StreamWriter(#"C:\Users\divya.kakumanu\Documents\Visual Studio 2010\Projects\XmlFile.xml");
try
{
mySerializer.Serialize(stream, emp);
}
catch (SerializationException ex)
{
throw;
}
finally
{
stream.Close();
}
you can tell the StreamWriter to append to the file instead of overwriting it using this constructor:
new StreamWriter("your-file-path", **true**);
Also...Why are you rethrowing that exception? And you should really put a using block around the StreamWriter

c# binary serialization "unexpected binary element: 225"

I am trying to save my custom class using binary serialization in c#. I have the serialization working fine (as far as I can tell, I get no errors) but when I try to deserialize it I get the following error:
SerializationException: Unexpected binary element: 255
Does anybody got ideas as to what could be causing this? I'm using C# with the Unity game engine.
EDIT:
Here's the code, it's inside the class for my editor window.
public static LevelMetaData LoadAllLevels()
{
string filepath = Path.Combine(Application.dataPath, "Levels/meta.dat");
BinaryFormatter serializer = new BinaryFormatter();
if (File.Exists(filepath))
{
using (StreamReader sr = new StreamReader(filepath))
{
return (LevelMetaData)serializer.Deserialize(sr.BaseStream);
}
}
else
{
LevelMetaData temp = new LevelMetaData();
using (StreamWriter sw = new StreamWriter(filepath))
{
serializer.Serialize(sw.BaseStream, temp);
}
return temp;
}
}
EDIT 2:
Here's the LevelMetaData class:
[Serializable]
public class LevelMetaData
{
public LevelMetaData()
{
keys = new List<string>();
data = new List<LevelController>();
}
public LevelController this[string key]
{
get
{
if (keys.Contains(key))
return data[keys.IndexOf(key)];
else
throw new KeyNotFoundException("Level with key \"" + key + "\"not found.");
}
}
public void Add(string key, LevelController level)
{
if (!keys.Contains(key))
{
keys.Add(key);
data.Add(level);
}
}
public bool Contains(string key)
{
return keys.Contains(key);
}
public List<string> keys;
public List<LevelController> data;
}
After some sleep and some more googling I found that I should be using the FileStream class instead of StreamReader and StreamWriter. Changing this makes it work.
I got this same error but it was due to a corrupt file created by the binary formatter serialization method. In my case, I observed that I had a JIT compilation error when serializing. This was somehow creating a file but with no correct data in it so whenever I tried to deserialized I got thie "unexpected binary element : 255" message.
Please, read this if you also find this behaviour on your serialization method.
It all reduces to use this line in the monobehavior using the formatter:
// Forces a different code path in the BinaryFormatter that doesn't rely on run-time code generation (which would break on iOS).
enter code here`Environment.SetEnvironmentVariable("MONO_REFLECTION_SERIALIZER", "yes");
For a further explanation of why are you needing this please visit the referenced link.
If you try adding the code solution and think it didn't help, you MUST uninstall the app from your device.
That's because of the data corruption on the file you attempt to create in the first place.
I had the issue, and that solve the problem.

Categories