将XML反序列化为对象时出错:System.FormatException 输入字符串格式不正确

23

您好,提前感谢您的帮助。 我在尝试使用XmlSerializer和StringReader将XElement反序列化为对象时遇到了问题。我的反序列化代码如下:

/*deseierialize a single RegisterServerObject instance from xml*/
        static RegisterServerObject DeserializeSingleServerFromXml(XElement serverElement)
        {
            XmlSerializer deserializer = new XmlSerializer(typeof(RegisterServerObject));
            RegisterServerObject server;
            using (var reader = new StringReader(serverElement.ToString()))
                server = (RegisterServerObject)deserializer.Deserialize(reader);

            return server;
        }

我知道通过异常揭示的读者内容是:

<Server>
  <ServerID>11</ServerID>
  <GroupID />
  <ParentID>15</ParentID>
  <ServerName>IAProd1</ServerName>
  <User>admin</User>
  <UID>123</UID>
  <PWD>password</PWD>
  <Domain>InputAccel</Domain>
  <Location>Left</Location>
  <AssociatedModules>
    <Module>
      <ModId>1</ModId>
      <ServerId>11</ServerId>
      <ModName>TestModA</ModName>
      <ModuleStatus>1</ModuleStatus>
    </Module>
    <Module>
      <ModId>2</ModId>
      <ServerId>11</ServerId>
      <ModName>TestModB</ModName>
      <ModuleStatus>1</ModuleStatus>
    </Module>
    <Module>
      <ModId>9</ModId>
      <ServerId>11</ServerId>
      <ModName>TestModI</ModName>
      <ModuleStatus>1</ModuleStatus>
    </Module>
    <Module>
      <ModId>10</ModId>
      <ServerId>11</ServerId>
      <ModName>TestModJ</ModName>
      <ModuleStatus>1</ModuleStatus>
    </Module>
  </AssociatedModules>
</Server>

我的RegisterServerObject类如下所示:

[XmlRoot("Server")]
    public class RegisterServerObject
    {
        public RegisterServerObject() { }

        public int ServerID { get; set; }

        public int GroupID { get; set; }

        public int ParentID { get; set; }

        public string ServerName { get; set; }

        public string User { get; set; }

        public int Uid { get; set; }

        public string Domain { get; set; }

        public string Location { get; set; }

        public List<RegisterModuleObject> AssociatedModules { get; set; }

    }

冒着信息过载的风险,我得到的确切异常消息是:

System.InvalidOperationException: There is an error in XML document (4, 4). ---> System.FormatException: Input string was not in a correct format.
   at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
   at System.Xml.XmlConvert.ToInt32(String s)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderRegisterServerObject.Read3_RegisterServerObject(Boolean isNullable, Boolean checkType)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderRegisterServerObject.Read4_Server()
   --- End of inner exception stack trace ---
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, Object events)
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle)
   at System.Xml.Serialization.XmlSerializer.Deserialize(TextReader textReader)
   at SL_xMonitor_Frontend_RefactorV1.Views.RegisteringNewChildWindowV2.DeserializeSingleServerFromXml(XElement serverElement)
   at SL_xMonitor_Frontend_RefactorV1.Views.RegisteringNewChildWindowV2.modXmlClient_getAssociatedModulesCompleted(Object sender, getAssociatedModulesCompletedEventArgs e)
   at SL_xMonitor_Frontend_RefactorV1.XMLServersAndModulesServiceReference.XMLTablesAndModulesServiceClient.OngetAssociatedModulesCompleted(Object state)}

看起来在将XML元素的值(可能是ParentID)转换为整数以实例化类时存在问题,但我不确定原因。提前感谢您的帮助!


为什么你将XElement传递给方法而不是XDoxument - user854301
现在代码的编写方式是,相关的XDocument实例由多个<server>条目及其自己的模块组成,我尝试将整个内容反序列化为一个类,但没有成功,所以我想拆分它 :) - Christian
3个回答

40

问题在于属性GroupID被声明为整数,但其值为空(<GroupID/>)。解决方案之一是更改XML,使该元素的值为有效的整数:

<GroupID>0</GroupID>

另一种解决方案是将该值反序列化为字符串,然后转换成整数以便类型的用户使用:

    [XmlRoot("Server")]
    public class RegisterServerObject
    {
        public RegisterServerObject() { }

        public int ServerID { get; set; }

        [XmlIgnore]
        public int GroupID { get; set; }
        [XmlElement(ElementName = "GroupID")]
        public string GroupIDStr
        {
            get
            {
                return this.GroupID.ToString();
            }
            set
            {
                if (string.IsNullOrEmpty(value))
                {
                    this.GroupID = 0;
                }
                else
                {
                    this.GroupID = int.Parse(value);
                }
            }
        }

        public int ParentID { get; set; }

        public string ServerName { get; set; }

        public string User { get; set; }

        public int Uid { get; set; }

        public string Domain { get; set; }

        public string Location { get; set; }

        [XmlArray(ElementName = "AssociatedModules")]
        [XmlArrayItem(ElementName = "Module")]
        public List<RegisterModuleObject> AssociatedModules { get; set; }
    }

    public class RegisterModuleObject
    {
        public int ModId { get; set; }
        public int ServerId { get; set; }
        public string ModName { get; set; }
        public int ModuleStatus { get; set; }
    }

感谢您的快速和完整的回复。它解决了抛出的异常并导致了大部分预期的行为。然而,创建的RegisterServerObject没有从xml中填充其AssociatedModules列表属性。您知道这是为什么吗?如果有什么我可以在代码中更改以使其发生?或者如果这只是我反序列化的方式的限制?再次感谢您的帮助。 - Christian
你没有在相关模块列表中填充模块,因为XML中的名称与类型名称不匹配。你可以使用[XmlArray][XmlArrayItem]修饰列表属性来定义预期的名称(就像我在更新的答案中所做的那样),或者使用[XmlType]来更改RegisterModuleObject类的XML名称。 - carlosfigueira
哇,太棒了。我已经纠正了名称不匹配的问题,但是使用的只是 [XmlElement] 标记,而不是像您指示的那样使用 [XmlArray][XmlArrayItem] 标记。再次感谢您的帮助,现在表现正确了。哇,XML反序列化非常巧妙。 - Christian

4

首先,您需要为 GroupID 属性设置 XmlIgnore 属性。

[XmlRoot("Server")]
public class RegisterServerObject
{
   . . .
   [XmlIgnore]
   public int GroupID { get; set; }
   . . .
}

然后您可以创建适配器,用于反序列化:

[XmlRoot("Server")]
public class RegisterServerObjectAdapter : RegisterServerObject
{
    [XmlElement("GroupID")]
    public string GroupIDNew
    {
        get { return GroupID.ToString(); }
        set
        {
            int outInt;
            int.TryParse(value, out outInt);
            GroupID = outInt;
        }
    }
}

最后,我稍微修改了DeserializeSingleServerFromXml方法

    static RegisterServerObject DeserializeSingleServerFromXml(XDocument serverElement)
    {
        var deserializer = new XmlSerializer(typeof(RegisterServerObjectAdapter));
        return (RegisterServerObject)deserializer.Deserialize(serverElement.CreateReader(ReaderOptions.OmitDuplicateNamespaces));
    }

1

可能是与GroupID有关的问题。由于没有提供GroupID的值,我认为它会尝试将其作为string.Empty传递,显然无法设置为int属性。

您可以尝试以下操作:

[XmlIgnore]
public int GroupID 
{
    get { !string.IsNullOrEmpty(GroupIDAsText) ? int.Parse(GroupIDAsText) : 0; }
    set { GroupID = value; }
}

[XmlAttribute("GroupID")
public int GroupIDAsText { get; set; }

.


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接