How to cache an array using IDistributedCache? - c#

I have a project that is written in C# on the top of ASP.NET Core 6 framework.
I need to cache data of type AppraisalResult[] using IDistributedCache.
I created the following class:
public class AppraisalCacheService : IAppraisalCacheService
{
private readonly IDistributedCache _distributedCache;
private readonly JsonSerializer _serializer;
public AppraisalCacheService(IDistributedCache distributedCache)
{
_distributedCache = distributedCache;
_serializer = new JsonSerializer();
}
public async Task<AppraisalResult[]> GetAsync(....)
{
// logic removed for simplicity
var key = GetKey(..);
var data = await _distributedCache.GetAsync(key);
if (data != null)
{
using MemoryStream ms = new MemoryStream(data);
using BsonDataReader reader = new BsonDataReader(ms);
return _serializer.Deserialize<AppraisalResult[]>(reader);
}
return null;
}
public async Task RemoveAsync(....)
{
// logic removed for simplicity
var key = GetKey(..);
await _distributedCache.RemoveAsync(key);
}
public async Task StoreAsync(AppraisalResult[] results, ....)
{
// logic removed for simplicity
var key = GetKey(..);
using MemoryStream ms = new MemoryStream();
using BsonDataWriter writer = new BsonDataWriter(ms);
_serializer.Serialize(writer, results);
await _distributedCache.SetAsync(key, ms.ToArray(), new DistributedCacheEntryOptions()
{
SlidingExpiration = TimeSpan.FromDays(7),
AbsoluteExpiration = DateTime.Now.AddDays(30),
});
}
private string GetKey(...)
{
// logic removed for simplicity
return "custom-key....";
}
}
The StoreAsync() method seems to be working fine. But, when I try to cast the cached value back into AppraisalResult[] it fails with the following error
{"Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'AppraisalResult[]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.\r\nTo fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.\r\nPath '0'."}
UPDATED
When trying to ready from the cache prior deserializeing I am getting an error. Here is the code that I tried
var data = await _distributedCache.GetAsync(key);
if (data != null)
{
using MemoryStream ms = new MemoryStream(data);
using BsonDataReader reader = new BsonDataReader(ms);
var dd = reader.ReadAsBytes();
}
The line reader.ReadAsBytes() throw the following exception before I deserialize:
{"Error reading bytes. Unexpected token: StartObject. Path '0'."}

It turned out that this is a limitation in Bson. You can't deserilize directly yo array object. The workaround was to create an object that contains the array property
public class AppraisalResultObj
{
public AppraisalResult[] Results { get; set; }
}
public class AppraisalCacheService : IAppraisalCacheService
{
private readonly IDistributedCache _distributedCache;
private readonly JsonSerializer _serializer;
public AppraisalCacheService(IDistributedCache distributedCache)
{
_distributedCache = distributedCache;
_serializer = new JsonSerializer();
}
public async Task<AppraisalResult[]> GetAsync(....)
{
// logic removed for simplicity
var key = GetKey(..);
var data = await _distributedCache.GetAsync(key);
if (data != null)
{
using MemoryStream ms = new MemoryStream(data);
using BsonDataReader reader = new BsonDataReader(ms);
var obj = _serializer.Deserialize<AppraisalResultObj>(reader);
return obj.Results;
}
return null;
}
public async Task RemoveAsync(....)
{
// logic removed for simplicity
var key = GetKey(..);
await _distributedCache.RemoveAsync(key);
}
public async Task StoreAsync(AppraisalResult[] results, ....)
{
// logic removed for simplicity
var key = GetKey(..);
using MemoryStream ms = new MemoryStream();
using BsonDataWriter writer = new BsonDataWriter(ms);
_serializer.Serialize(writer, new AppraisalResultObj(){
Results = results
});
await _distributedCache.SetAsync(key, ms.ToArray(), new DistributedCacheEntryOptions()
{
SlidingExpiration = TimeSpan.FromDays(7),
AbsoluteExpiration = DateTime.Now.AddDays(30),
});
}
private string GetKey(...)
{
// logic removed for simplicity
return "custom-key....";
}
}
then the code

Related

How to to serialize a class with a private dictionary member into a file?

I am trying to write functions that save a type, the Dispatcher type shown below, into a file, and then reload it later. I wrote that following functions, but they are not working. I get an exception:
Exception thrown: 'System.InvalidOperationException' in System.Xml.dll
Elsewhere I read that maybe because the member in the class is private then I should use BinaryFormatter, but it did not work.
What am I doing wrong ?
(The Dispatcher class will be used to store messages and also will allow users to pull messages from it. so I want to backup the data in case of an error and then be able to reload it).
public class Dispatcher
{
private Dictionary<int, Dictionary<int, Dictionary<int, Message>>> m_DataBase;
private Dispatcher()
{
m_DataBase = new Dictionary<int, Dictionary<int, Dictionary<int, Message>>>();
}
public static Dispatcher LoadFromFile()
{
Dispatcher loadedDataBase;
try
{
using (Stream stream = new FileStream(#".\DispatcherDataBase.xml", FileMode.Open))
{
XmlSerializer serializer = new XmlSerializer(typeof(Dispatcher));
loadedDataBase = serializer.Deserialize(stream) as Dispatcher;
}
}
catch (Exception)
{
loadedDataBase = new Dispatcher();
}
return loadedDataBase;
}
public void SaveToFile()
{
FileMode wantedFileModeForStream;
try
{
if (File.Exists(#".\DispatcherDataBase.xml"))
{
wantedFileModeForStream = FileMode.Truncate;
}
else
{
wantedFileModeForStream = FileMode.CreateNew;
}
using (Stream stream = new FileStream(#".\DispatcherDataBase.xml", wantedFileModeForStream))
{
XmlSerializer serializer = new XmlSerializer(this.GetType());
serializer.Serialize(stream, this);
}
}
catch (Exception)
{
}
}
}
You are trying to use XmlSerializer to serialize your Dispatcher type and are encountering three separate problems:
XmlSerializer requires your type to have a public parameterless constructor.
XmlSerializer does not support dictionaries.
XmlSerializer will not serialize non-public members such as m_DataBase.
DataContractSerializer (as well as DataContractJsonSerializer) do not have these limitations. If you mark your Dispatcher type with data contract attributes you will be able to serialize it to XML using this serializer.
Thus if you modify your type as follows:
public static class Constants
{
public const string DataContractNamespace = ""; // Or whatever
}
[DataContract(Name = "Dispatcher", Namespace = Constants.DataContractNamespace)]
public partial class Dispatcher
{
[DataMember]
private Dictionary<int, Dictionary<int, Dictionary<int, Message>>> m_DataBase;
private Dispatcher()
{
m_DataBase = new Dictionary<int, Dictionary<int, Dictionary<int, Message>>>();
}
[System.Runtime.Serialization.OnDeserialized]
void OnDeserializedMethod(System.Runtime.Serialization.StreamingContext context)
{
// Ensure m_DataBase is not null after deserialization (DataContractSerializer does not call the constructor).
if (m_DataBase == null)
m_DataBase = new Dictionary<int, Dictionary<int, Dictionary<int, Message>>>();
}
internal const string FileName = #"DispatcherDataBase.xml";
public static Dispatcher LoadFromFile()
{
Dispatcher loadedDataBase;
try
{
using (var stream = new FileStream(FileName, FileMode.Open))
{
var serializer = new DataContractSerializer(typeof(Dispatcher));
loadedDataBase = serializer.ReadObject(stream) as Dispatcher;
}
}
catch (Exception)
{
loadedDataBase = new Dispatcher();
}
return loadedDataBase;
}
public void SaveToFile()
{
using (var stream = new FileStream(FileName, FileMode.Create))
using (var writer = XmlWriter.Create(stream, new XmlWriterSettings { Indent = true })) // Optional indentation for readability only.
{
var serializer = new DataContractSerializer(this.GetType());
serializer.WriteObject(writer, this);
}
}
}
// Not shown in question, added as an example
[DataContract(Name = "Message", Namespace = Constants.DataContractNamespace)]
public class Message
{
[DataMember]
public string Value { get; set; }
}
You will be able to round-trip your Dispatcher class to XML. Demo fiddle #1 here.
Alternatively, you could use DataContractJsonSerializer and serialize to JSON by simply swapping serializers and eliminating the optional XmlWriter:
public static Dispatcher LoadFromFile()
{
Dispatcher loadedDataBase;
try
{
using (var stream = new FileStream(FileName, FileMode.Open))
{
var serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(Dispatcher));
loadedDataBase = serializer.ReadObject(stream) as Dispatcher;
}
}
catch (Exception)
{
loadedDataBase = new Dispatcher();
}
return loadedDataBase;
}
public void SaveToFile()
{
using (var stream = new FileStream(FileName, FileMode.Create))
{
var serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(this.GetType());
serializer.WriteObject(stream, this);
}
}
Demo fiddle #2 here, which results in a fairly simple, clean-looking serialization format:
{"m_DataBase":[{"Key":1,"Value":[{"Key":2,"Value":[{"Key":3,"Value":{"Value":"hello"}}]}]}]}
json.net could also be used to serialize this type if you are willing to use a 3rd party component.

How do I return correctly formatted name:value pairs from mongodb, using the C# mongo driver [duplicate]

I am working with the MongoDB C# driver. I have a BsonDocument with some data which includes some MongoDB-specific types (like ObjectIDs and ISODates). I want to convert this to a valid general-purpose JSON string. In other words, I can't have something like _id: ObjectId(...) or date: ISODate(...) but would prefer _id: "..." and date: "...". Basically, I want to convert these special types that only MongoDB recognizes to regular strings so they can be parsed more easily. The problem is that a built-in function like .ToJson() (which another StackOverflow answer suggests) doesn't really convert the document to valid JSON at all because it maintains these special types. My document also contains many levels of arrays and sub-documents, so a simple for loop will not suffice. What's the best way to convert a BsonDocument that avoids this problem? I would prefer something built-in rather than manually recursing through the document to fix all the issues.
MongoDB.Bson (2.5+) has support to map between BsonValues and .Net objects.
BsonTypeMapper Class
To map a BsonValue (or BsonDocument) to .Net object use
var dotNetObj = BsonTypeMapper.MapToDotNetValue(bsonDoc);
You can then use your choice of serialization library. For example,
JsonConvert.SerializeObject(dotNetObj);
If you have a List of BsonDocument
var dotNetObjList = bsonDocList.ConvertAll(BsonTypeMapper.MapToDotNetValue);
I've ran into the same thing, you can get valid JSON via:
var jsonWriterSettings = new JsonWriterSettings { OutputMode = JsonOutputMode.Strict };
JObject json = JObject.Parse(postBsonDoc.ToJson<MongoDB.Bson.BsonDocument>(jsonWriterSettings));
However it will return something like:
{"_id":{"$oid":"559843798f9e1d0fe895c831"}, "DatePosted":{"$date":1436107641138}}
I'm still trying to find a way to flatten that.
In my opinion the best option is to use Newtonsoft.Json.Bson.BsonReader.
Here a complete example:
public string ToJson(BsonDocument bson)
{
using (var stream = new MemoryStream())
{
using (var writer = new BsonBinaryWriter(stream))
{
BsonSerializer.Serialize(writer, typeof(BsonDocument), bson);
}
stream.Seek(0, SeekOrigin.Begin);
using (var reader = new Newtonsoft.Json.Bson.BsonReader(stream))
{
var sb = new StringBuilder();
var sw = new StringWriter(sb);
using (var jWriter = new JsonTextWriter(sw))
{
jWriter.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
jWriter.WriteToken(reader);
}
return sb.ToString();
}
}
}
I think that this should handle all cases correctly (dates, ids, ...).
Most of the Time for this I use, Json.NET
JsonConvert.SerializeObject(obj);
Most of the time that does the trick. If need be you can set some JsonSerializerSettings
Through experimentation I discovered that there is an option that makes this method output proper JSON:
BsonDocument myBsonDocument = ... //code that loads a BSON document
myBsonDocument.ToJson(new JsonWriterSettings { OutputMode = JsonOutputMode.RelaxedExtendedJson})
Result:
{ "_id" : { "$oid" : "5fb7a33e73152101d6610e9d" }, "moreProperties" : "moreValues" }
Here is the way i did it, to skip mongodb _id entry.
var collection = _database.GetCollection<BsonDocument>("test");
var result = await collection.Find(new BsonDocument())
.Project(Builders<BsonDocument>.Projection.Exclude("_id"))
.ToListAsync();
var obj = result.ToJson();
what about
String json = result.toJson(JsonWriterSettings.builder().objectIdConverter(new Converter<ObjectId>() {
#Override
public void convert(ObjectId value, StrictJsonWriter writer) {
writer.writeString(value.toHexString());
}
}).build());
If the contents of the BSON document is saved as, below
{
"Date" : "2019-04-05T07:07:31.979Z",
"BSONCONTENT" : {
"_t" : "MongoDB.Bson.BsonDocument, MongoDB.Bson",
"_v" : {
"A" : "XXXX",
"B" : 234
}
}
}
then it works with generic class.
private static T ProcessBsonConversion<T>(BsonDocument data)
{
var content = data.GetElement("_v");
var jsonDataContent= content.Value.AsBsonValue.ToJson();
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(jsonDataContent);
}
My problem had to do with how DotNet Core WebAPI serializes an object to json. If you return a string from a method that is formatted as json, WEBAPI will serialize it to json again. This is only needed if you are working with a generic BsonDocument to save to MongoDb.
[HttpGet()]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<string>> GetAsync()
{
return Ok(ret.ToJson());
}
Fix
[HttpGet()]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<object>> GetAsync()
{
var doc = await _collection.Find(...).FirstOrDefaultAsync();
return Ok(JObject.Parse(doc.ToJson()));
}
Since Davide Icardi answer is deprecated so:
Install Newtonsoft.Json.Bson package
Replace BsonReader with BsonDataReader.
Your extension method should be like this:
using MongoDB.Bson;
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Bson;
using System.IO;
using System.Text;
namespace YourNamespaceGoesHere
{
public static class BsonHelpers
{
public static string ToNormalJson(BsonDocument bson)
{
using (var stream = new MemoryStream())
{
using (var writer = new BsonBinaryWriter(stream))
{
BsonSerializer.Serialize(writer, typeof(BsonDocument), bson);
}
stream.Seek(0, SeekOrigin.Begin);
using (var reader = new BsonDataReader(stream))
{
var sb = new StringBuilder();
var sw = new StringWriter(sb);
using (var jWriter = new JsonTextWriter(sw))
{
jWriter.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
jWriter.WriteToken(reader);
}
return sb.ToString();
}
}
}
}
}
This should generate the expected normal valid JSON string you're looking for :)
If you need to use this ASP.NET Core for when you may be returning a model that has BsonDocument to be able to add dynamic data. You can use this JsonConverter implementation based on MarkKGreenway's answer!
public class BsonDocumentJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(BsonDocument);
}
public override bool CanRead
{
get
{
return false;
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
//string json = (value as BsonDocument).ToJson(); //!NB: this returns BSON not JSON. Why on earth is it called ToJson!?
string json = JsonConvert.SerializeObject(value);
writer.WriteRawValue(json);
}
}
Then in your Startup.cs just add the following.
services.AddMvc()
.AddJsonOptions(options => options.SerializerSettings.Converters.Add(new BsonDocumentJsonConverter()));

UWP Json to C# conversion

I want to serialize some json data I get from the web to classes and use the data, so I went to http://json2csharp.com/ and turned the json as below
json: [{"line_descr":"\u03a0\u0395\u0399\u03a1\u0391\u0399\u0391\u03a3 -
\u0392\u039f\u03a5\u039b\u0391","line_descr_eng":"PEIRAIAS - VOYLA"}]
To this class:
public class RootObject
{
public string line_descr { get; set; }
public string line_descr_eng { get; set; }
}
This is my code:
class LineName
{
public async static Task<RootObject> GetLineName(int linecode)
{
var http = new HttpClient();
var response = await http.GetAsync("http://telematics.oasa.gr/api/?act=getLineName&p1=962");
var result = await response.Content.ReadAsStringAsync();
var serializer = new DataContractJsonSerializer(typeof(RootObject));
var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
var data = (RootObject)serializer.ReadObject(ms);
return data;
}
}
[DataContract]
public class RootObject
{
[DataMember]
public string line_descr { get; set; }
[DataMember]
public string line_descr_eng { get; set; }
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
RootObject myLine = await LineName.GetLineName(92);
ResultTextBlock.Text = myLine.line_descr_eng;
}
So when I try to get the data and display it in my textblock I get the error: line_descr_eng is null.
Can someone point where the fault is ? since the line_descr_eng should be
PEIRAIAS - VOYLA but mine is null and after a lot of searching I cant find where the fault is.
Your json is an array, not an object, and you should deserialize it into an array.
public async static Task<RootObject[]> GetLineName(int linecode)
{
var http = new HttpClient();
var response = await http.GetAsync("http://telematics.oasa.gr/api/?act=getLineName&p1=962");
var result = await response.Content.ReadAsStringAsync();
var serializer = new DataContractJsonSerializer(typeof(RootObject[]));
var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
var data = (RootObject[])serializer.ReadObject(ms);
return data;
}
//...
var myLines = await LineName.GetLineName(92);
var myLine = myLines.FirstOrDefault();
Also you don't need a memory stream, you can read stream from the http response
var result = await response.Content.ReadAsStreamAsync();
You simple can use the JavaScriptSerializer class instead of DataContractJsonSerializer like this:
Replace:
var serializer = new DataContractJsonSerializer(typeof(RootObject));
var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
var data = (RootObject)serializer.ReadObject(ms);
with this:
var ser = new JavaScriptSerializer();
var test = ser.Deserialize<List<RootObject>>(json);
If you cannot find JavaScriptSerializer, then you have to do the simple following steps:
Right click References and do Add Reference, then from Assemblies->Framework select System.Web.Extensions.
Now you should be able to add the following to your class file:
using System.Web.Script.Serialization;
Cited from: https://stackoverflow.com/a/15391388/5056173

Cannot cast a System.Type to byte[]

I have a n-tier business application project incorporating C#/VB.NET and am having issues getting an update method to communicate between layers. In my data layer that is closest to my database, I have a GetByID() method that finds an employee based on their ID within the database, and places in a dictionary their title, first name etc as well as the entity as a whole (serialized).
In the next layer up (businessuser), I am trying to set its private members to the results of the businessuser GetByID() method that calls the data layers GetByID() method. It is here where I am trying to set my private member
_entity = (byte[])retDict["entity"];
Which gives me the error cannot implicitly type byte[] to System.Type since _entity is a Type.
The presentation layer done in VB, passes an employeeID via a listview selection value, which is then in turn passed down to the user layer and to the data layer.
Here is the EmployeeBusinessData layer GetByID() code:
public byte[] GetByID(int empid)
{
Dictionary<string, Object> retDict = new Dictionary<string, Object>();
try
{
HelpDeskDBEntities dbContext = new HelpDeskDBEntities();
dbContext.Configuration.ProxyCreationEnabled = false;
Employee EmployeeEntity = dbContext.Employees.FirstOrDefault(emp => emp.EmployeeID == empid);
if (EmployeeEntity != null)
{
retDict["title"] = EmployeeEntity.Title;
retDict["firstname"] = EmployeeEntity.FirstName;
retDict["lastname"] = EmployeeEntity.LastName;
retDict["phoneno"] = EmployeeEntity.PhoneNo;
retDict["email"] = EmployeeEntity.Email;
retDict["departmentid"] = EmployeeEntity.DepartmentID;
retDict["employeeid"] = EmployeeEntity.EmployeeID;
retDict["entity"] = Serializer(EmployeeEntity, true);
}
else
{
retDict["error"] = "Employee not found!";
}
}
catch (Exception ex)
{
ErrorRoutine(ex, "EmployeeBusinessData", "GetByID");
}
return Serializer(retDict);
}
And the EmployeeBusinessUser layer GetById():
public byte[] GetByID(int empid)
{
Dictionary<string, Object> retDict = new Dictionary<string, object>();
try
{
EmployeeBusinessData empData = new EmployeeBusinessData();
retDict = (Dictionary<string, Object>)Deserializer(empData.GetByID(empid));
_employeeID = Convert.ToInt32(retDict["employeeid"]);
_title = Convert.ToString(retDict["title"]);
_firstName = Convert.ToString(retDict["firstname"]);
_lastName = Convert.ToString(retDict["lastname"]);
_phoneNo = Convert.ToString(retDict["phoneno"]);
_email = Convert.ToString(retDict["email"]);
_departmentID = Convert.ToInt32(retDict["departmentid"]);
_entity = (byte[])retDict["entity"];
}
catch (Exception ex)
{
ErrorRoutine(ex, "EmployeeUserData", "GetByID");
}
return Serializer(retDict);
}
Here is the Serializer method code as well, it's the same in both class .dlls:
public static byte[] Serializer(Object inObject, bool bIsEntity = false)
{
byte[] ByteArrayObject;
if (bIsEntity) //If the entity uses DataContractSerializer
{
MemoryStream strm = new MemoryStream();
var serializer = new DataContractSerializer(inObject.GetType());
serializer.WriteObject(strm, inObject);
ByteArrayObject = strm.ToArray();
}
else
{
BinaryFormatter frm = new BinaryFormatter();
MemoryStream strm = new MemoryStream();
frm.Serialize(strm, inObject);
ByteArrayObject = strm.ToArray();
}
return ByteArrayObject;
}
private Type _entity;
Two different types for Deserializer:
public static Object Deserializer(byte[] ByteArrayIn, Type entityType)
{
MemoryStream stream = new MemoryStream(ByteArrayIn);
DataContractSerializer ser = new DataContractSerializer(entityType);
Object returnObject = ser.ReadObject(stream);
return returnObject;
}
public static Object Deserializer(byte[] ByteArrayIn)
{
BinaryFormatter frm = new BinaryFormatter();
MemoryStream strm = new MemoryStream(ByteArrayIn);
Object returnObject = frm.Deserialize(strm);
return returnObject;
}
How can I get retDict["entity"] to cast to a byte so I can assign it to _entity?
Here's your problem:
private Type _entity;
You probably want an Employee object instead, like so:
private Employee _entity;
Or if you want a variable that can hold any kind of object (or entity), then use the object type:
private object _entity;
A Type in .NET is the class that represents the type of a class, not a class itself.
So if I have a class like so:
public class Person
{
}
I can store it in an Person variable:
Person somePerson = new Person();
Or in an object variable:
object someObject = new Person();
But I can only store the type of an object in a Type variable:
Type someType = typeof(Person);
Or if you have an instance of an object you can get its type as follows:
Person somePerson = new Person();
Type typeOfSomePerson = somePerson.GetType();
But chances are you don't want the type at all.
EDIT:
I noticed you aren't deserializing twice in your question. You are first serializing the entity and then separately serializing its fields. I am not sure why you are serializing everything twice. But at the very least you need to deserialize it twice.
So change this:
_entity = (byte[])retDict["entity"];
To this:
_entity = (Employee)Deserialize((byte[])retDict["entity"], typeof(Employee));
This is effectively saying, "Retrieve the serialized bytes of the Employee from the dictionary, deserialize the bytes into an Employee instance, and cast it as an Employee since the return type of the method is object."
But like I said, it seems you are doing each field twice. You should only have to serialize the entity itself once, then deserialize the entity back again. Unless there is something I am missing with your logic.

Problem xml-deserializing recursive nested object

Solved: code below is not causing an infinite loop as I thought. the loop was in the code calling the deserialization. this posted code works just fine
I am trying to serialize and deserialize to xml the following object
public class MessageObjectCollection : List<MessageObject>
{
public string Serialize()
{
return XmlObjectSerializer.SerializeObject(this);
}
public static MessageObjectCollection DeSerialize(string serializedPriceHistory)
{
return XmlObjectSerializer.DeserializeObject<MessageObjectCollection>(serializedPriceHistory);
}
}
The MessageObject class looks like this
public class MessageObject
{
public string Title;
public MessageObjectCollection Responses;
}
So if I have a instance of messageobjectcollection that looks like:
var msgColl = new MessageObjectCollection
{
new MessageObject
{
Title = "Hello",
Responses = new MessageObjectCollection
{
new MessageObject
{
Title = "hi",
Responses = null
}
}
}
}
I can serialize this just fine by calling
var xml = msgColl.Serialize();
However when I try to deserialize this by calling
var msgColl = new MessageObjectCollection().Deserialize(xml);
I get an stack overflow exception in the deserialization method:
public static T DeserializeObject<T>(string xml)
{
T result;
var ser = new XmlSerializer(typeof(T));
var buffer = StringToUTF8ByteArray(xml);
using (var stream = new MemoryStream(buffer, 0, buffer.Length))
{
result = (T) ser.Deserialize(stream);
}
return result;
}
Anyone know what I'm doing wrong?
Im not sure if its relevant to the problem but as the Deserialize method is static shouldn't you be calling...
var msgColl = MessageObjectCollection.Deserialize(xml);
instead of...
var msgColl = new MessageObjectCollection().Deserialize(xml);
??

Categories