I am trying to pass in a type object to pass to the serializer.
internal void SerializeXML(Object ObjType, String XMLRoot, Object Output, String Filename)
{
XmlSerializer serializer = new XmlSerializer(typeof(ObjType), new XmlRootAttribute(XMLRoot));
StreamReader reader = new StreamReader(System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(Filename));
Output = (Type)serializer.Deserialize(reader);
reader.Close();
}
And I want to call it by (Main.LanguageList.Language is a class):
SerializeXML(Main.LanguageList.Language, "Language", LanguageListFile, InternalLangListXML);
I am getting Object is a variable but is used as a type.
It'd be more elegant to write a generic method:
internal void DeserializeXML<T>(String XMLRoot, T Output, String Filename)
{
XmlSerializer serializer = new XmlSerializer(typeof(T), new XmlRootAttribute(XMLRoot));
StreamReader reader = new StreamReader(System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(Filename));
Output = (T)serializer.Deserialize(reader);
reader.Close();
}
And call it like this:
DeserializeXML<Main.LanguageList.Language>("Language", LanguageListFile, InternalLangListXML);
Also, it'd suggest changing the method to return the result instead of relying on an output parameter:
internal T DeserializeXML<T>(String XMLRoot, String Filename)
{
XmlSerializer serializer = new XmlSerializer(typeof(T), new XmlRootAttribute(XMLRoot));
using (StreamReader reader = new StreamReader(System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(Filename)))
{
return (T)serializer.Deserialize(reader);
}
}
It can then be called like this:
var result = DeserializeXML<Main.LanguageList.Language>("Language", InternalLangListXML);
Related
I have a method that returns object from .xml file
(please don't mind resource usage and naming, it's just an example)
public static T FromXMLFile<T>(string filePath)
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
FileStream fs = new FileStream(filePath, FileMode.Open);
XmlTextReader xmlTextReader = new XmlTextReader(fs);
if(xmlSerializer.CanDeserialize(xmlTextReader))
{
object tempObject = (T)xmlSerializer.Deserialize(xmlTextReader );
xmlTextReader.Close();
return (T)tempObject;
}
else
return default(T);
}
Now I would like to do the same but with with string instead of a file. I came up with something like this (again, simplified example)
public static T FromString<T>(string inputString)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
T result;
try
{
using (TextReader reader = new StringReader(inputString))
{
result = (T)serializer.Deserialize(reader);
}
return result;
}
catch //temporary solution, finally should stick to .CanDeserialize(xmlTextReader) usage
{
return default(T);
}
}
How would I use .CanDeserialize() in this case?
Rather than using the Deserialize(TextReader) overload, create an XmlReader from the TextReader, and use that XmlReader for both the Deserialize and CanDeserialize calls:
using (TextReader reader = new StringReader(inputString))
using (XmlReader xmlReader = XmlReader.Create(reader))
{
if (serializer.CanDeserialize(xmlReader))
{
result = (T)serializer.Deserialize(xmlReader);
}
}
This approach - with both read and write - also allows you to supply additional reader/writer settings for fine-grained control of the API.
I am reading a NetworkStream for json string and then deserializing it using Newtonsoft.Json.
Sometimes, two json objects could be sent back-to-back and read at the same time on the stream. But the Newtonsoft.Json serializer gives me only one object.
For example, if I have the following string on the stream:
{"name":"John Doe","age":10}{"name":"Jane Doe","age":10}
If I deserialize the stream, the serializer reads the entire stream, but gives only the first object.
Is there a way to make the serializer read only the first object from the stream and then read the next object in the next iteration of a loop?
Code:
public static Person Deserialize(Stream stream)
{
var Serializer = new JsonSerializer();
var streamReader = new StreamReader(stream, new UTF8Encoding());
return Serializer.Deserialize<Person>(new JsonTextReader(streamReader));
}
I cannot deserialize as a list because I'm not receiving a json array.
I think you can do it like this:
public static IList<Person> Deserialize(Stream stream) {
var serializer = new JsonSerializer();
var streamReader = new StreamReader(stream, new UTF8Encoding());
var result = new List<Person>();
using (var reader = new JsonTextReader(streamReader)) {
reader.CloseInput = false;
// important part
reader.SupportMultipleContent = true;
while (reader.Read()) {
result.Add(serializer.Deserialize<Person>(reader));
}
}
return result;
}
Important part is SupportMultipleContent property, which notifies reader that there might be multiple json objects side to side.
you can try it doing like this
var httpRequest = HttpContext.Current.Request;
// This list will have all the stream objects
var persons = new List<Person>();
if (httpRequest.Files.Count > 0)
{
for (var obj = 0; doc < httpRequest.Files.Count; obj++)
{
var postedFile = httpRequest.Files[obj];
var bytes = new byte[postedFile.ContentLength];
postedFile.InputStream.Read(bytes, 0, postedFile.ContentLength);
persons.Add(Serializer.Deserialize<Person>(new JsonTextReader(new StreamReader(new MemoryStream(bytes)))));
}
}
I got a weird problem where I can serialize a derived class if I put it in a List but not when it stands on it own.
I am using these methods to serialize and deserialize (found them here):
public static string Serialize(T obj)
{
using (MemoryStream memoryStream = new MemoryStream())
using (StreamReader reader = new StreamReader(memoryStream))
{
DataContractSerializer serializer = new DataContractSerializer(obj.GetType());
serializer.WriteObject(memoryStream, obj);
memoryStream.Position = 0;
return reader.ReadToEnd();
}
}
public static T Deserialize(string xml, Type toType)
{
using (Stream stream = new MemoryStream())
{
byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
stream.Write(data, 0, data.Length);
stream.Position = 0;
DataContractSerializer deserializer = new DataContractSerializer(toType);
return (T)deserializer.ReadObject(stream);
}
}
I have a base class Entity. And a derived class Thing.
[DataContract]
[KnownType(typeof(Thing))]
Class Entity
{
}
[DataContract]
Class Thing : Entity
{
}
Now, when I try to serialize an object instantiated as Thing there is no problem but the deserialization gives an error.
Thing e = new Thing();
string xmlstring = XML<Entity>.Serialize(e);
Entity testE = XML<Entity>.Deserialize(xmlstring, typeof(Entity));
The error says something like Expected element Entity from ... . Element Thing was found. (Was not written in english.)
But the weird thing is that it works if I put the object into a list and serialize-deserialize the list.
Thing e = new Thing();
List<Entity> test = new List<Entity>();
test.Add(e);
var xmlstring = XML<List<Entity>>.Serialize(test);
List<Entity> test2 = XML<List<Entity>>.Deserialize(xmlstring, typeof(List<Entity>));
Now test2 has an entry with the a correct Thing-item. Even if this could be a workaround it surely must be an easier way and it must be something that would be easy to fix I think? Any thoughts? What did I miss?
(And of course it works when deserializing my Thingobject as a Thing-object but that's not what I want, when deserializing I will not know the class on beforehand.)
Seems that I have found a workaround myself after thinking about #Jaya's comment. I modified the serialize method to force it to serialize to the base class type. Originally I did not think this would work, but it did!
public static string Serialize(T obj, Type toType)
{
using (MemoryStream memoryStream = new MemoryStream())
using (StreamReader reader = new StreamReader(memoryStream))
{
DataContractSerializer serializer = new DataContractSerializer(toType);
serializer.WriteObject(memoryStream, obj);
memoryStream.Position = 0;
return reader.ReadToEnd();
}
}
I was given a XSD file and sample XML file, and asked to post the XML file to a URL.
Sample XML file
<?xml version="1.0"?>
<pingRequest>
<elt></elt>
...
</pingRequest>
I'm familiar with SOAP and REST, but I have never done posting pure XML file directly. Here is what I got so far.
1) Generate C# class from XSD file
xsd.exe Test.xsd /c
2) Serialize from C# class to XML using XmlSerializer
public string SerializeObject(object obj, Type type)
{
string xml;
var xs = new XmlSerializer(type);
using (var ms = new MemoryStream())
{
xs.Serialize(ms, obj, null);
ms.Position = 0;
using (var sr = new StreamReader(memoryStream))
{
xml = sr.ReadToEnd();
}
}
return xml;
}
OR Should I use LINQ to XML to generate XML file?
3) Post XML to URL using WebClient
var client = new WebClient();
var uri = new Uri("http://www.site.com/");
string responseXML = client.UploadString(uri, requestXML);
Am I at the right track? If not, could you please point me to a right direction? Thanks in advance.
Here is my partial code so that other can use it.
First, created two classes based on XML tags using xsd.exe Test.xsd /c (for both request and response), so that I do not have to prase the XML files manually.
public pingResponse Send()
{
var pingRequest = new pingRequest
{
myelement = "test"
};
// Serialize pingRequest class to xml
var serializer = new Serializer();
string requestXml = serializer.SerializeObject(pingRequest, typeof(pingRequest));
// Post xml
var client = new WebClient();
var uri = new Uri("http://www.site.com/");
string responseXML = client.UploadString(uri, requestXML);
return (pingResponse)serializer.DeserializeObject(xml, typeof(Response));
}
public class Serializer
{
public string SerializeObject(object obj, Type type)
{
var setting = new XmlWriterSettings() {OmitXmlDeclaration = true, Indent = true};
var xml = new StringBuilder();
using (var writer = XmlWriter.Create(xml, setting))
{
var nsSerializer = new XmlSerializerNamespaces();
nsSerializer.Add(string.Empty, string.Empty);
var xmlSerializer = new XmlSerializer(type);
xmlSerializer.Serialize(writer, obj, nsSerializer);
}
return xml.ToString();
}
public object DeserializeObject(string xml, Type type)
{
var xs = new XmlSerializer(type);
var stringReader = new StringReader(xml);
var obj = xs.Deserialize(stringReader);
stringReader.Close();
return obj;
}
}
Note: I do not include the PingRequest and PingResponse classes since my member variables will not be same as yours.
I have a generic class as follows:
class myClass<T>
{
public T[] m_SomeData;
}
I want to implement a generic method to read data from a file and populate the data fields of this class. Something like:
class myClass<T>
{
public T[] m_SomeData;
public void ReadData(string fileName);
}
An implementation of the ReadData methods looks something like this (all error checking removed for brevity):
void ReadData(string fileName)
{
TextReader rdr = new StreamReader(fileName);
string line = rdr.ReadLine();
// Here I need to parse value of type T from the line
// and initialize the m_SomeData array
// How do I do that? I would like to keep it generic if possible
}
Note, I can guarantee the type T is numeric, at least by convention
Update: OP would like human readable output. I would suggest JavaScriptSerializer, then, in:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Web.Extensions.dll
// Serialize:
using (var fs = new FileStream(fileName, FileMode.Create))
using (var writer = new StreamWriter(fs))
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
string s = serializer.Serialize(m_SomeData);
writer.Write(s);
}
// Deserialize:
using (var fs = new FileStream(fileName, FileMode.Open))
using (var reader = new StreamReader(fs))
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
var s = reader.ReadToEnd();
m_SomeData = serializer.Deserialize<T[]>(s);
}
Old Answer:
This is a job for BinaryFormatter:
using (FileStream fs = new FileStream(fileName, FileMode.Open))
{
BinaryFormatter formatter = new BinaryFormatter();
m_SomeData = (T[])formatter.Deserialize(fs);
}
This of course assumes you are also using it to serialize via formatter.Serialize(fs, m_SomeData);.