I have a program that takes objects stored as XML in a database (basicly a message queue) and de-serializes them. Intermittently, I will get one of the following errors:
<You can pre-create serializers: http://msdn.microsoft.com/en-us/library/bk3w6240%28v=VS.100%29.aspx Just give it a try. The next canonical candidate for such problems is your virus scanner. Your tool is writing to disc while creating serializers. I have seen virus scanner producing all kind of strange errors in such situations.
This is a sign that you are not caching your serialisers which is not good at all => it leads to memory leak and I suspect you will experience this.
Remember that .NET generates code and compiles them into assemblies every time you create a serialiser.
Always create your serialisers and then cache them.
Here is a sample:
public class SerialiserCache
{
private static readonly SerialiserCache _current = new SerialiserCache();
private Dictionary<Type, XmlSerializer> _cache = new Dictionary<Type, XmlSerializer>();
private SerialiserCache()
{
}
public static SerialiserCache Current
{
get { return _current; }
}
public XmlSerializer this[Type t]
{
get
{
LoadIfNecessary(t);
return _cache[t];
}
}
private void LoadIfNecessary(Type t)
{
// double if to prevent race conditions
if (!_cache.ContainsKey(t))
{
lock (_cache)
{
if (!_cache.ContainsKey(t))
{
_cache[t] = new XmlSerializer(typeof(T));
}
}
}
}
}
For the first error (cannot execute a program), you might be running into the same XmlSerializer bug that we ran into. It turns out XmlSerlializer throws that exception when Directory.CurrentDirectory is set to a folder that no longer exists.
Our specific situation is different than yours, but I'll give the details in case it helps shed light on what might be happening for you, or it helps anyone else. In our case, a small number of our customers would get that error after launching our WinForms application directly from the installer, i.e. they chose the "run now" option after installing or upgrading. (Unclear why it happened to some but not others). What we suspect is happening is that our installer (InstallAware) occasionally starts our application with the current directory set to a folder that no longer exists, or is about to be deleted. To test this theory, I wrote a test app which simulates launching from the installer:
string dir = @"C:\Users\me\Documents\Temp\WillBeDeleted";
Directory.CreateDirectory(dir);
Directory.SetCurrentDirectory(dir);
Process.Start(@"C:\Program Files (x86)\...\our.exe");
Directory.SetCurrentDirectory(@"C:\"); // otherwise, won't be able to delete
Directory.Delete(dir);
Sure enough, as soon as the launched application created a new instance of XmlSerializer, the exception would be thrown. I put in trace statements to show the result of GetCurrentDirectory(), and indeed it was set to the WillBeDeleted folder. The fix was to SetCurrentDirectory to a valid location during application initialization, before any serialization took place.
XmlSerializer is supposed to be thread safe.
Even if that's the case, you can notice the behavior you are getting is in both cases failing at: XmlSerializer..ctor(Type type)
Given that, it seriously look like a multi-threading limitation trying to create serializers.
I suggest to take this code you have:
public XmlSerializer GetSerializer(Type t) {
if (!SerializerCache.ContainsKey(t.FullName)) {
SerializerCache.Add(t.FullName, new XmlSerializer(t)); // Error occurs here, intermittently
}
return SerializerCache[t.FullName];
}
And implement a lock on the Add. This way you are only creating 1 serializer at a time. The hit is small if you aren't processing tons of different types.
Note that you need the lock anyway, as the way it is you could get duplicate exceptions when 2 types try to be added at the same time.
static object serializerCacheLock = new object();
public XmlSerializer GetSerializer(Type t) {
if (!SerializerCache.ContainsKey(t.FullName))
lock(serializerCacheLock)
if (!SerializerCache.ContainsKey(t.FullName)) {
SerializerCache.Add(t.FullName, new XmlSerializer(t));
}
return SerializerCache[t.FullName];
}
If the above still isn't enough, I'd try with a read/write lock on serializer constructor vs. serializers usage. Line of thought being that maybe the multi-threading issue is worth than 2 ctors running at the same time.
All above is a Huge guess, but if it were me I'd definitely confirm is not that.