Dynamic invoke is the method that allows you to Invoke a delegate of a type you don't know at runtime (uses some reflection inside).
A good thing to use as a pattern is to invoke a Delegate d as:
try
{
d.DynamicInvoke();
}
catch (System.Reflection.TargetInvocationException ex)
{
HandleException(ex);
}
where handleexception does:
void HandleException(Exception ex)
{
if (ex != null && ex.InnerException != null)
throw ex.InnerException;
if (ex != null)
throw ex;
throw new Exception("Unhandled exception");
}
Meaning it rethrows the innerexception to the application, instead of the boxed one.
Wednesday, November 21, 2007
XmlSerializer problem
I encountered a problem with XmlSerializer these days.
What it does is that it serializes OK a string with a character from range 0x01-0x20, but at deserialization it throws exception:
{"There is an error in XML document (6, 14)."}
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle)
at System.Xml.Serialization.XmlSerializer.Deserialize(Stream stream)
It reproduces as:
Create a C#.Net class:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Serialization;
namespace whatever
{
[Serializable]
[XmlRoot("FooRoot")]
public class Foo
{
static XmlSerializer internalSerializer = new XmlSerializer(typeof(Foo));
public byte[] Serialize()
{
using (System.IO.MemoryStream MS = new System.IO.MemoryStream())
{
internalSerializer.Serialize(MS, this);
return MS.ToArray();
}
}
public static Foo Deserialize(byte[] val)
{
using (System.IO.MemoryStream MS = new System.IO.MemoryStream(val))
{
try
{
object obj = internalSerializer.Deserialize(MS);
return (Foo)obj;
}
catch (Exception ex)
{
throw new Exception("Whoops", ex);
}
}
}
object _internalContainer;
[XmlElement("OBJInside", typeof(FooWhateverSerializableObject))]
public object ObjectContainer
{
get
{
return _internalContainer;
}
set
{
_internalContainer=value;
}
}
}
}
Now add the code in main:
Foo foo= new Foo();
FooWhateverSerializableObject fwso=new FooWhateverSerializableObject();
fwso.MessageText="dsd"+System.Text.Encoding.UTF8.GetString(new byte[]{6}) +" ";
foo.ObjectContainer=fwso;
byte[] fooB=MM.Serialize();
string s = System.Text.Encoding.UTF8.GetString(fooB);//here it spits out character 0x06 as "" meaning it escapes the unpermitted char.
Message M2=Message.Deserialize(fooB);//here crashes, due to the "bug"
What you should do to fix it?
Replace:
using (System.IO.MemoryStream MS = new System.IO.MemoryStream(val))
{
object obj = internalSerializer.Deserialize(MS);
}
with:
using (System.IO.MemoryStream MS = new System.IO.MemoryStream(val))
{
using (XmlTextReader XTR = new XmlTextReader(MS))
{
object obj = internalSerializer.Deserialize(XTR);
}
}
meaning you pass a XMLReader(XMLTextReader) instead of a Stream to the XmlSerializer.Deserialize method.
Why?
Because the method Deserialize(stream), analyzed with Reflector, does:
public object Deserialize(Stream stream)
{
XmlTextReader xmlReader = new XmlTextReader(stream);
xmlReader.WhitespaceHandling = WhitespaceHandling.Significant;
xmlReader.Normalization = true;
xmlReader.XmlResolver = null;
return this.Deserialize(xmlReader, (string) null);
}
while Deserialize(XmlReader) calls Deserialize(xmlReader, string) and skips setting Normalization property to true for the XMLTextReader (default is false).
Conclusion
I don't know wheter this is a bug or it's by design, but clearly it wasted some time for me. As the final advice, don't pass a stream to the XMLSerializer.Deserialize method, but a XMLReader instead.
What it does is that it serializes OK a string with a character from range 0x01-0x20, but at deserialization it throws exception:
{"There is an error in XML document (6, 14)."}
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle)
at System.Xml.Serialization.XmlSerializer.Deserialize(Stream stream)
It reproduces as:
Create a C#.Net class:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Serialization;
namespace whatever
{
[Serializable]
[XmlRoot("FooRoot")]
public class Foo
{
static XmlSerializer internalSerializer = new XmlSerializer(typeof(Foo));
public byte[] Serialize()
{
using (System.IO.MemoryStream MS = new System.IO.MemoryStream())
{
internalSerializer.Serialize(MS, this);
return MS.ToArray();
}
}
public static Foo Deserialize(byte[] val)
{
using (System.IO.MemoryStream MS = new System.IO.MemoryStream(val))
{
try
{
object obj = internalSerializer.Deserialize(MS);
return (Foo)obj;
}
catch (Exception ex)
{
throw new Exception("Whoops", ex);
}
}
}
object _internalContainer;
[XmlElement("OBJInside", typeof(FooWhateverSerializableObject))]
public object ObjectContainer
{
get
{
return _internalContainer;
}
set
{
_internalContainer=value;
}
}
}
}
Now add the code in main:
Foo foo= new Foo();
FooWhateverSerializableObject fwso=new FooWhateverSerializableObject();
fwso.MessageText="
foo.ObjectContainer=fwso;
byte[] fooB=MM.Serialize();
string s = System.Text.Encoding.UTF8.GetString(fooB);//here it spits out character 0x06 as "" meaning it escapes the unpermitted char.
Message M2=Message.Deserialize(fooB);//here crashes, due to the "bug"
What you should do to fix it?
Replace:
using (System.IO.MemoryStream MS = new System.IO.MemoryStream(val))
{
object obj = internalSerializer.Deserialize(MS);
}
with:
using (System.IO.MemoryStream MS = new System.IO.MemoryStream(val))
{
using (XmlTextReader XTR = new XmlTextReader(MS))
{
object obj = internalSerializer.Deserialize(XTR);
}
}
meaning you pass a XMLReader(XMLTextReader) instead of a Stream to the XmlSerializer.Deserialize method.
Why?
Because the method Deserialize(stream), analyzed with Reflector, does:
public object Deserialize(Stream stream)
{
XmlTextReader xmlReader = new XmlTextReader(stream);
xmlReader.WhitespaceHandling = WhitespaceHandling.Significant;
xmlReader.Normalization = true;
xmlReader.XmlResolver = null;
return this.Deserialize(xmlReader, (string) null);
}
while Deserialize(XmlReader) calls Deserialize(xmlReader, string) and skips setting Normalization property to true for the XMLTextReader (default is false).
Conclusion
I don't know wheter this is a bug or it's by design, but clearly it wasted some time for me. As the final advice, don't pass a stream to the XMLSerializer.Deserialize method, but a XMLReader instead.
Always use EndInvoke for each BeginInvoke you call
Let's say you have the delegate:
delegate void Foo(string x);
And a method that does some job and then it might crash. (here crashes always).
void Method(string txt)
{
//do code here;
throw new Exception("Unhandled exception never caught unless a debugger attached");
}
And another method that starts the first one asynchronous on a thread pool thread.
void CallingMethodAsynch()
{
Foo delegFoo=this.Method;
delegFoo.BeginInvoke("text",null,null);
}
The most common mistake made by programmer lazyness is passing null,null as parameters on BeginInvoke.
This brings strange scenarios into your multithreaded application by never discovering some exceptions; the thread will be aborted and you will never be noticed inside your app unless you do some advanced coding or simply use the asynch pattern.
The usual pattern would be to add the method:
void CallBackMethod(IAsynchResult aRes)
{
if(aRes==null OR aRes.AsynchState==null)
return;
Foo deleg=aRes.AsynchState as Foo;
if(Foo==null)
return;
Foo.EndInvoke(aRes);
}
and replace BeginInvoke("text", null, null) with BeginInvoke("text", CallBackMethod, foo);
This means that in case an unhandled exception happened on the sepparate thread, you will trap the error on EndInvoke - either put a catch or let it propagate.
I encourage to avoid catching errors in multithreaded apps, let the error propagate, crash the application, analyze the crash and improve your code, rather than catching errors and have a bad performance on your app.
A few usefull links(some oldie but good):
http://msdn2.microsoft.com/en-us/library/ms810439.aspx
http://weblogs.asp.net/justin_rogers/articles/126345.aspx
delegate void Foo(string x);
And a method that does some job and then it might crash. (here crashes always).
void Method(string txt)
{
//do code here;
throw new Exception("Unhandled exception never caught unless a debugger attached");
}
And another method that starts the first one asynchronous on a thread pool thread.
void CallingMethodAsynch()
{
Foo delegFoo=this.Method;
delegFoo.BeginInvoke("text",null,null);
}
The most common mistake made by programmer lazyness is passing null,null as parameters on BeginInvoke.
This brings strange scenarios into your multithreaded application by never discovering some exceptions; the thread will be aborted and you will never be noticed inside your app unless you do some advanced coding or simply use the asynch pattern.
The usual pattern would be to add the method:
void CallBackMethod(IAsynchResult aRes)
{
if(aRes==null OR aRes.AsynchState==null)
return;
Foo deleg=aRes.AsynchState as Foo;
if(Foo==null)
return;
Foo.EndInvoke(aRes);
}
and replace BeginInvoke("text", null, null) with BeginInvoke("text", CallBackMethod, foo);
This means that in case an unhandled exception happened on the sepparate thread, you will trap the error on EndInvoke - either put a catch or let it propagate.
I encourage to avoid catching errors in multithreaded apps, let the error propagate, crash the application, analyze the crash and improve your code, rather than catching errors and have a bad performance on your app.
A few usefull links(some oldie but good):
http://msdn2.microsoft.com/en-us/library/ms810439.aspx
http://weblogs.asp.net/justin_rogers/articles/126345.aspx
Subscribe to:
Posts (Atom)