Why Doesn't Xmlserializer Support Dictionary

Why doesn't XmlSerializer support Dictionary?

Hashtables need hashcode and equality comparer providers generally. These cant be serialized easily in XML, and definitely will not be portable.

But I think you already found your answer. Just serialize the hashtable as a List<KeyValuePair<K,V>> and then (re)construct it into a hashtable.

Why isn't there an XML-serializable dictionary in .NET?

The thing about XML Serialization is that it's not just about creating a stream of bytes. It's also about creating an XML Schema that this stream of bytes would validate against. There's no good way in XML Schema to represent a dictionary. The best you could do is to show that there's a unique key.

You can always create your own wrapper, for instance One Way to Serialize Dictionaries.

Serialize dictionary to XML C#

As UserSessionLookupTable is non-static object so its lifespan is with the life span of parent. As long you are using same instance of UserSessionCapturePlugin for all users, this will hold record of all the users.

If you are creating different instance of UserSessionLookupTable for each request that will hold only record of last user.

Also XmlSerializer can't serialize Dictionary directly.

To correct the behaviour and keep record of all the user sessions, I suggest to modify the way you are saving session session info.

  • Before saving new user session info, first load and deserialize existing xml, add new record in it, serialize again and save to file. (You need to make sure if that is first time, file will not exists so handle that)
  • Before removing user session info, first load and deserialize existing xml, remove record that you want to remove, serialize again and save it back to file.

Here is some snippet

Dictionary<Guid, UserSessionInfo> LoadUserSessionData()
{
try
{
var serializer = new XmlSerializer(typeof(KeyValuePair<Guid, UserSessionInfo>[]));

using (var stream = new FileStream(@"UserSessionLookupDictionarySerialized.xml", FileMode.Open))
{
var sessionData = (KeyValuePair<Guid, UserSessionInfo>[])serializer.Deserialize(stream)
return sessionData.ToDictionary(i => i.Key, i => i.Value);
}
}
catch (FileNotFoundException)
{
return new Dictionary<int, UserSessionInfo>();
}
}

void SaveUserSessionData(Dictionary<Guid, UserSessionInfo> sessionData)
{
var serializer = new XmlSerializer(typeof(KeyValuePair<Guid, UserSessionInfo>[]));

using (var stream = new FileStream(@"UserSessionLookupDictionarySerialized.xml", FileMode. OpenOrCreate))
{
serializer.Serialize(stream, sessionData.ToArray());
}
}

After that OnSessionChange will looks like this

public void OnSessionChange(SessionChangeDescription changeDescription)
{
switch (changeDescription.Reason)
{
//Case of Logon
case SessionChangeReason.SessionLogon:
//CreateRunningProcessesLog("UserSession-SessionLogon");

UserSession userSessionLogin = new UserSession()
{
UserName = MachineHelper.GetUsername(),
UserGuid = MachineHelper.GetUserGuid(),
MachineGuid = MachineHelper.GetMachineGUID(),
LoginTime = DateTime.Now.ToUniversalTime(),
SessionGuid = Guid.NewGuid(), //New Guid generated for tracking the UserSession, this will be created on on logon
IsReadable = false,
SessionId = changeDescription.SessionId,
};

UserSessionInfo userSessionInfoLogin = new UserSessionInfo()
{
UserName = MachineHelper.GetUsername(),
SessionGuid = userSessionLogin.SessionGuid,
IsActiveUser = true,
SessionId = changeDescription.SessionId,
LoginTime = userSessionLogin.LoginTime,
State = RowState.Added,
};

var userSessionLookupTable = LoadUserSessionData();
userSessionLookupTable.Add(userSessionInfoLogin.SessionId, userSessionInfoLogin);
SaveUserSessionData(userSessionLookupTable);
break;

//Case of Logoff
case SessionChangeReason.SessionLogoff:
UserSession userSessionLogoff = new UserSession()
{
UserName = MachineHelper.GetUsername(),
UserGuid = MachineHelper.GetUserGuid(),
MachineGuid = MachineHelper.GetMachineGUID(),
LogOffTime = DateTime.Now.ToUniversalTime(),
IsReadable = true,
SessionId = changeDescription.SessionId,
};

var userSessionLookupTable = LoadUserSessionData();
userSessionLookupTable.Remove(userSessionLogoff.SessionId);
SaveUserSessionData(userSessionLookupTable);
break;
}
}

Serialize Class containing Dictionary member

You can't serialize a class that implements IDictionary. Check out this link.

Q: Why can't I serialize hashtables?

A: The XmlSerializer cannot process
classes implementing the IDictionary
interface. This was partly due to
schedule constraints and partly due to
the fact that a hashtable does not
have a counterpart in the XSD type
system. The only solution is to
implement a custom hashtable that does
not implement the IDictionary
interface.

So I think you need to create your own version of the Dictionary for this. Check this other question.

How to XML-serialize a dictionary

Take a look at the following blog post

  • http://blogs.msdn.com/b/psheill/archive/2005/04/09/406823.aspx
  • http://web.archive.org/web/20100703052446/http://blogs.msdn.com/b/psheill/archive/2005/04/09/406823.aspx

and this one (not in english, but the code is useful)

  • http://huseyint.com/2007/12/xml-serializable-generic-dictionary-tipi/

Code sample from: http://web.archive.org/web/20100703052446/http://blogs.msdn.com/b/psheill/archive/2005/04/09/406823.aspx

using System.Collections.Generic;
using System.Collections;
using System.IO;
using System.Xml.Serialization;
using System.Xml;
using System;
public static void Serialize(TextWriter writer, IDictionary dictionary)
{
List<Entry> entries = new List<Entry>(dictionary.Count);
foreach (object key in dictionary.Keys)
{
entries.Add(new Entry(key, dictionary[key]));
}
XmlSerializer serializer = new XmlSerializer(typeof(List<Entry>));
serializer.Serialize(writer, entries);
}
public static void Deserialize(TextReader reader, IDictionary dictionary)
{
dictionary.Clear();
XmlSerializer serializer = new XmlSerializer(typeof(List<Entry>));
List<Entry> list = (List<Entry>)serializer.Deserialize(reader);
foreach (Entry entry in list)
{
dictionary[entry.Key] = entry.Value;
}
}
public class Entry
{
public object Key;
public object Value;
public Entry()
{
}

public Entry(object key, object value)
{
Key = key;
Value = value;
}
}

It generates output like the following, when the keys and values are strings.

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfEntry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Entry>
<Key xsi:type="xsd:string">MyKey</Key>
<Value xsi:type="xsd:string">MyValue</Value>
</Entry>
<Entry>
<Key xsi:type="xsd:string">MyOtherKey</Key>
<Value xsi:type="xsd:string">MyOtherValue</Value>
</Entry>
</ArrayOfEntry>

Deserialize XML to Dictionary

Try this:

var dic = xdc.Descendants("ArrayOfTableRow1")
.Elements()
.ToDictionary(x => x.Element("Code").Value,
x => x.Element("Explanation").Value);

You don't want Descendants of ArrayOfTableRow1, you want only the immediate children, so use Elements. Then, as you loop over each TableRow1, grab the Code and Explanation values.

Note that this doesn't include any error handling.

Reading from XML to Dictionary using XmlSerializer?

I think the approach would be to back it with a dictionary, and present the List for the serialization. Like this:

public List<Publisher> Publishers
{
get { return _PublishersDictionary.Select(x => x.Value).ToList(); }
set { _publishersDictionary = value.ToDictionary(x => x.Name, x => x); }
}
private Dictionary<string, Publisher> _publishersDictionary;

[XmlIgnore]
public Dictionary<string, Publisher> PublisherDictionary
{
get { return _publishersDictionary; }
}


Related Topics



Leave a reply



Submit