在上一篇文章《ubuntu 8.10 server配置mono2.0.1运行asp.net 2.0 》中提到,在mono中进行自定义的XmlSerializer时发生异常。
发生异常的是在一个自定义的DataTable序列化(使用IXmlSerializable)中,异常信息是:
Cannot cast from source type to destination type.
Description: HTTP 500. Error processing request.
Stack Trace:
System.InvalidCastException: Cannot cast from source type to destination type. at System.Xml.XmlWriter.WriteValue (System.Object value) [0x00000] at xDB.Examples.Employee.WriteXml (System.Xml.XmlWriter writer) [0x00000] at System.Xml.Serialization.XmlSerializationWriter.WriteSerializable (IXmlSerializable serializable, System.String name, System.String ns, Boolean isNullable, Boolean wrapped) [0x00000] at System.Xml.Serialization.XmlSerializationWriter.WriteSerializable (IXmlSerializable serializable, System.String name, System.String ns, Boolean isNullable) [0x00000] at System.Xml.Serialization.XmlSerializationWriterInterpreter.WriteObject (System.Xml.Serialization.XmlTypeMapping typeMap, System.Object ob, System.String element, System.String namesp, Boolean isNullable, Boolean needType, Boolean writeWrappingElem) [0x00000] at System.Xml.Serialization.XmlSerializationWriterInterpreter.WriteRoot (System.Object ob) [0x00000] at System.Xml.Serialization.XmlSerializer.Serialize (System.Object o, System.Xml.Serialization.XmlSerializationWriter writer) [0x00000] at System.Xml.Serialization.XmlSerializer.Serialize (System.Xml.XmlWriter writer, System.Object o, System.Xml.Serialization.XmlSerializerNamespaces namespaces) [0x00000] |
通过分析,可以看出是XmlWriter在写入时候发生了类型转换的错误。通过跟踪错误,发现是在序列化Int16的类型时抛出的异常,难道是mono平台下不支持Int16类型?
于是我写了一段测试代码:
- public class Serializer : IHttpHandler
- {
- public void ProcessRequest(HttpContext context)
- {
- context.Response.ContentType = "text/xml";
- XmlSerializer serializer = new XmlSerializer(typeof(Employee));
- Int16 id = 12;
- serializer.Serialize(context.Response.Output,new Employee(id,"xud",false));
- }
- public bool IsReusable
- {
- get
- {
- return false;
- }
- }
- }
- public class Employee : IXmlSerializable
- {
- public Employee()
- {
- }
- public Employee(Int16 employeeId,string employeeName,bool deleted)
- {
- this.EmployeeId = employeeId;
- this.EmployeeName = employeeName;
- this.Deleted = deleted;
- }
- Int16 _employeeId;
- public Int16 EmployeeId
- {
- get { return _employeeId; }
- set { _employeeId = value; }
- }
- string _employeeName;
- public string EmployeeName
- {
- get { return _employeeName; }
- set { _employeeName = value; }
- }
- bool _deleted;
- public bool Deleted
- {
- get { return _deleted; }
- set { _deleted = value; }
- }
- #region IXmlSerializable 成员
- public System.Xml.Schema.XmlSchema GetSchema()
- {
- throw new Exception("The method or operation is not implemented.");
- }
- public void ReadXml(XmlReader reader)
- {
- throw new Exception("The method or operation is not implemented.");
- }
- public void WriteXml(XmlWriter writer)
- {
- writer.WriteStartElement("Employee");
- writer.WriteStartElement("EmployeeId");
- writer.WriteValue(this.EmployeeId);
- writer.WriteEndElement();
- writer.WriteStartElement("EmployeeName");
- writer.WriteValue(this.EmployeeName);
- writer.WriteEndElement();
- writer.WriteStartElement("Deleted");
- writer.WriteValue(this.Deleted);
- writer.WriteEndElement();
- writer.WriteEndElement();
- }
- #endregion
- }
- }
编译运行后发现序列化完全正常!看来不是Int16的问题。
经过分析,忽然想起在DataTable中取值的时候取回的都是object类型,于是我又小小改动了一下代码:
- writer.WriteValue((object)this.EmployeeId);
编译...运行...呵呵,可爱的异常又出现了!!!
看来是mono平台在进行装箱、拆箱的时候有点小小的bug,同样的字符串转换,仅仅是包装不同?
通过修改我自己的代码,将其加上Convter.ToString(value)后,该异常得到解决。
在解决的这个问题后,我又直接使用DataTable自己的序列化功能,在mono下能正常使用。通过Reflector跟踪发现,在直接使用DataTable进行XmlSerializer的时候,是通过DataStorge类来进行字符串转换的,可惜由于是internal类,我们无法直接使用。