Reputation: 3935
We have a serialization issue which only happens in .NET 4.5 - same code works fine in .NET 4. we're trying to serialize an inherited type with a few fields, both base and inherited class are marked with SerializableAttribute. We get an exception on the client side of Web service saying that there was a MethodAccessException in the server , the server itself does not throw any exceptions , it seems to be a problem in the client serialization process. It is important to note that we are compiling in .NET 4- not .4.5
Update: After implementing the ISerailize and ignoring the "Value" property the program did run correctly, but it means we had to give up on serializing this field.
any help would be most appreciated. Thanks, Omer
The exception details:
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:
Attached is the base and inherited classes code: Base:
[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
}
Intheried:
[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
}
Upvotes: 15
Views: 16186
Reputation: 180
I recently had the same issue, and found the actual cause and the proper solution.
This problem is caused by the XML serializer testing the default value of a property/field. If the field value matches the DefaultValue attribute, it will not serialize it to save space. There is no overload for DefaultValue of type "decimal", so a decimal value will be converted to a float, which is one of the overloads.
You have to explicitly tell the attribute it is a decimal:
[DevaultValue(typeof(decimal), "1.56")]
Be aware that using DefaultValue on a field will not set that field to that value on deserialization. You still have to set the correct value in your constructor, or as a field initializer:
[DefaultValue(typeof(decimal), "1.56")]
decimal MyValue { get; set; } = 1.56;
Upvotes: 0
Reputation: 538
I had a also such a serialization failure. In my case it was caused by a type mismatch of the [DefaultValue(..)]
attributes. I had an attached default value of "1.0d"
(a double) for a property of type decimal
. It seems that the new implementation of the XmlSerializer can't convert such values anymore but the old one could. There is also the option to switch back to the old version of XmlSerializer by adding an attribute in 'App.config' but this is not recommended by Microsoft (and me). Hope this helps someone.
Upvotes: 3
Reputation: 274
We're looking to address this issue in upcoming .NET Framework 4.5 Update. I'll update the post with the download link as soon as update is released. Please contact netfx45compat at Microsoft dot com if you have mission critical app that's impacted, and fix is required urgently. I can help direct you to Microsoft support that can help with your request.
Upvotes: 4
Reputation: 12395
I looked at your types more closely, and the problem is likely caused by a conflict between:
public virtual object @Value
{
}
on the Base and:
private new object Value
{
}
on the Derived class. Here are two things I would try:
Upvotes: 1
Reputation: 12395
In 4.5, the implementation of XmlSerializer was replaced with one that isn't dependent on the C# compiler. While it provides better startup performance and stability, you might be running into a compatibility issue between the implementations. Can you try adding the following to your app.config file and see if that fixes the issue?
<configuration>
<system.xml.serialization>
<xmlSerializer useLegacySerializerGeneration="true"/>
</system.xml.serialization>
</configuration>
If you're concerned about having this work on 4.0, you could try detecting the version of the framework at runtime, and dynamically change the configuration if the runtime is 4.5 or higher. I wrote a blog post a while back explaining how to do that:
Upvotes: 17