【问题标题】:Serialization breaks in .NET 4.5.NET 4.5 中的序列化中断
【发布时间】:2013-02-04 14:53:39
【问题描述】:

我们有一个仅在 .NET 4.5 中发生的序列化问题 - 相同的代码在 .NET 4 中工作正常。我们正在尝试序列化具有几个字段的继承类型,基类和继承类都标有 可序列化属性。我们在Web服务的客户端得到一个异常,说服务端有一个MethodAccessException,服务端本身并没有抛出任何异常,这似乎是客户端序列化过程的问题。 需要注意的是,我们是在 .NET 4 而非 .4.5 中编译的

更新:在实现 ISerailize 并忽略“Value”属性后,程序确实运行正常,但这意味着我们不得不放弃序列化该字段。

任何帮助将不胜感激。谢谢, 奥马尔

异常详情:

System.Web.Services.Protocols.SoapException occurred
  HResult=-2146233087
  Message=System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> System.InvalidOperationException: There was an error generating the XML document. ---> System.MethodAccessException: Attempt by method 'Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write88_DeviceSiteTypeInfo(System.String, System.String, IOSIGHT.Info.DeviceSiteTypeInfo, Boolean, Boolean)' to access method 'IOSIGHT.Info.DeviceSiteTypeInfo.get_Value()' failed.
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write88_DeviceSiteTypeInfo(String n, String ns, DeviceSiteTypeInfo o, Boolean isNullable, Boolean needType)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write1310_GetSiteTypesResponse(Object[] p)
   at Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer2089.Serialize(Object objectToSerialize, XmlSerializationWriter writer)
   at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
   --- End of inner exception stack trace ---
   at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
   at System.Web.Services.Protocols.SoapServerProtocol.WriteReturns(Object[] returnValues, Stream outputStream)
   at System.Web.Services.Protocols.WebServiceHandler.WriteReturns(Object[] returnValues)
   at System.Web.Services.Protocols.WebServiceHandler.Invoke()
   --- End of inner exception stack trace ---
  Source=System.Web.Services
  Actor=""
  Lang=""
  Node=""
  Role=""
  StackTrace:
       at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
       at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
       at IOSIGHT.BLL.localhost.IOSightWS.GetSiteTypes() in C:\IOSIGHT\Common\IOSight.BLL\Web References\localhost\Reference.cs:line 25019
       at IOSIGHT.BLL.TypeBankBLL.GetSiteTypes() in C:\IOSIGHT\Common\IOSight.BLL\Entities\TypeBanksBLL.cs:line 477
  InnerException: 

附加的是基类和继承类代码: 基础

[Serializable()]
public class TypeBankInfo
{


    #region "Fields"
    private int _id = 0;
    private string _Name = string.Empty;
    private string _description = string.Empty;
    private object _value = null;

    #endregion

    #region "Constructors"
    public TypeBankInfo()
    {
    }

    public TypeBankInfo(int ID, string name)
        : this()
    {
        this._id = ID;
        this.Name = name;
    }

    public TypeBankInfo(int ID, string name, string description)
        : this(ID, name)
    {
        this._description = description;
        this._value = Value;
    }

    public TypeBankInfo(int ID, string name, string description, object value)
        : this(ID, name, description)
    {
        this._value = value;
    }

    #endregion

    #region "Properties"
    public virtual string Name
    {
        get
        {
            return this._Name;
        }
        set
        {
            this._Name = value;
        }
    }

    public virtual string Description
    {
        get
        {
            return _description;
        }
        set
        {
            _description = value;
        }
    }

    public virtual int ID
    {
        get
        {
            return _id;
        }
        set
        {
            _id = int.Parse(value.ToString());
        }
    }


    public virtual object @Value
    {
        get
        {
            return this._value;
        }
        set
        {
            this._value = value;
        }
    }

    #endregion

}

继承

[Serializable()]
public class DeviceSiteTypeInfo : TypeBankInfo, ISerializable
{


    #region "Fields"
    private EntityTypeEnum _entitytype = EntityTypeEnum.Site;
    private DeviceIOTemplateInfo[] _IOTemplates;
    private CaptionInfo[] _Captions;
    private int _parentClassID;
    #endregion

    #region "Constructors"
    public DeviceSiteTypeInfo()
    {
    }

    public DeviceSiteTypeInfo(int id, string name)
        : base(id, name)
    {
    }

    public DeviceSiteTypeInfo(int id, string name, string description)
        : base(id, name, description)
    {
    }

    // The special constructor is used to deserialize values. 
    public DeviceSiteTypeInfo(SerializationInfo info, StreamingContext context)
    {
        //parent  fields
        ID = (int)info.GetValue("_id", typeof(int));
        Name = (string)info.GetValue("_Name", typeof(string));
        Description = (string)info.GetValue("_description", typeof(string));


        //my fields
        _entitytype = (EntityTypeEnum)info.GetValue("_entitytype", typeof(EntityTypeEnum));
        _IOTemplates = (DeviceIOTemplateInfo[])info.GetValue("_IOTemplates", typeof(DeviceIOTemplateInfo[]));
        _Captions = (CaptionInfo[])info.GetValue("_Captions", typeof(CaptionInfo[]));
        _parentClassID = (int)info.GetValue("_parentClassID", typeof(int));

    }



    #endregion

    #region "Properties"
    public EntityTypeEnum EntityTypeID
    {
        get
        {
            return this._entitytype;
        }
        set
        {
            this._entitytype = value;
        }
    }



    [EditorBrowsable(EditorBrowsableState.Never), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    private new object Value
    {
        get
        {
            return base.Value;
        }
        set
        {
            base.Value = value;
        }
    }

    public CaptionInfo[] Captions
    {
        get
        {
            return this._Captions;
        }
        set
        {
            this._Captions = value;
        }
    }

    public DeviceIOTemplateInfo[] IOTemplates
    {
        get
        {
            return this._IOTemplates;
        }
        set
        {
            this._IOTemplates = value;
        }
    }

    public int ParentClassID
    {
        get
        {
            return this._parentClassID;
        }
        set
        {
            this._parentClassID = value;
        }
    }

    #endregion


    #region Methods

   /// <summary>
   /// Called on serialization
   /// </summary>
   /// <param name="info">serialiation info</param>
   /// <param name="context">context</param>
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        // parent fields
        info.AddValue("_id", ID, typeof(int));
        info.AddValue("_Name", Name, typeof(string));
        info.AddValue("_description", Description, typeof(string));

        //my fields
        info.AddValue("_entitytype", _entitytype, typeof(EntityTypeEnum));
        info.AddValue("_IOTemplates", _IOTemplates, typeof(DeviceIOTemplateInfo[]));
        info.AddValue("_Captions", _Captions, typeof(CaptionInfo[]));
        info.AddValue("_parentClassID", _parentClassID, typeof(int));
    }

    #endregion

}

【问题讨论】:

  • 你能用调用堆栈发布实际的异常吗?

标签: c# web-services serialization .net-4.5


【解决方案1】:

在 4.5 中,XmlSerializer 的实现被替换为不依赖于 C# 编译器的实现。虽然它提供了更好的启动性能和稳定性,但您可能会遇到实现之间的兼容性问题。您可以尝试将以下内容添加到您的 app.config 文件中,看看是否能解决问题?

<configuration>
  <system.xml.serialization>
    <xmlSerializer useLegacySerializerGeneration="true"/>
  </system.xml.serialization>
</configuration>

如果您担心在 4.0 上进行这项工作,您可以尝试在运行时检测框架的版本,并在运行时为 4.5 或更高版本时动态更改配置。不久前我写了一篇博文,解释了如何做到这一点:

http://blogs.msdn.com/b/youssefm/archive/2010/01/21/how-to-change-net-configuration-files-at-runtime-including-for-wcf.aspx

【讨论】:

  • 感谢您的建议。我在 .NET 4 中编译我的代码,而不是 .NET 4.5 - 所以这个属性不适用于我。问题出在“Value”属性上,我怀疑它的属性没有正确序列化
  • @omerschleifer 你确定它不适用吗?即使您为 .Net 4.0 编译,如果安装了 .Net 4.5,您的代码实际上也会在 .Net 4.5 下运行。
  • 谢谢,这确实有帮助。它还可以防止在服务器端的调试会话中由相同的序列化问题造成的 Visual Studio 崩溃。但是,由于我们在 .NET 4 中编译,并且此代码受源代码控制,因此任何不在 .Net 4.5 下的计算机都无法加载配置文件。未安装 .NET 4.5 框架的客户也是如此
  • 我已经更新了答案。您可以使用此答案检测是否安装了 4.5:stackoverflow.com/questions/199080/…。您也许还可以检查 mscorlib 的次要版本。
【解决方案2】:

我们希望在即将发布的 .NET Framework 4.5 更新中解决此问题。更新发布后,我将使用下载链接更新帖子。如果您有受影响的关键任务应用程序,请联系 Microsoft dot com 的 netfx45compat,并且迫切需要修复。我可以帮助您获得 Microsoft 支持,该支持可以帮助您处理您的请求。

【讨论】:

【解决方案3】:

我也遇到过这样的序列化失败。在我的情况下,它是由 [DefaultValue(..)] 属性的类型不匹配引起的。对于decimal 类型的属性,我附加了"1.0d"(双精度值)的默认值。似乎 XmlSerializer 的新实现不能再转换这些值,但旧实现可以。还可以选择通过在“App.config”中添加属性来切换回旧版本的 XmlSerializer,但 Microsoft(和我)不建议这样做。希望这对某人有所帮助。

【讨论】:

    【解决方案4】:

    我更仔细地查看了您的类型,问题可能是由以下冲突引起的:

    public virtual object @Value
    {
    }
    

    在基地和:

    private new object Value
    {
    }
    

    关于派生类。以下是我会尝试的两件事:

    1. 尝试公开“新对象值”。可能存在成员访问问题。
    2. 尝试将 Base 的“@Value”重命名为“BaseValue”或其他合适的名称。您使用“@”符号可能有问题。

    【讨论】:

      【解决方案5】:

      我最近遇到了同样的问题,并找到了真正的原因和正确的解决方案。

      此问题是由 XML 序列化程序测试属性/字段的默认值引起的。如果字段值与 DefaultValue 属性匹配,则不会对其进行序列化以节省空间。 “十进制”类型的 DefaultValue 没有重载,因此十进制值将转换为浮点数,这是重载之一。

      你必须明确告诉属性它是一个小数:

      [DevaultValue(typeof(decimal), "1.56")]
      

      请注意,在字段上使用 DefaultValue 不会在反序列化时将该字段设置为该值。您仍然必须在构造函数中设置正确的值,或者作为字段初始值设定项:

      [DefaultValue(typeof(decimal), "1.56")]
      decimal MyValue { get; set; } = 1.56;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-14
        • 2011-11-23
        相关资源
        最近更新 更多