locked
Xml serializing an object that implements INotifyPropertyChanged

    Question

  • Is there any way around this bug, I get the error

     

    System.InvalidOperationException : Unable to generate a temporary class (result=1).
    error CS0012: The type 'System.ComponentModel.INotifyPropertyChanged' is defined in an assembly that is not referenced. You must add a reference to assembly 'System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.

     

    I have tried applying the Attribute [XmlInclude(typeof(INotifyPropertyChanged))] with no luck.

    Thursday, January 31, 2008 3:58 PM

Answers

  • Success!

     

    I have found a reproducable new bug in XmlSerializer!

     

    No doubt this will turn out to be "by design" but nonetheless I am relieved to be able to move on with my project.

     

    How I found it

    So, I copied my entire project to another location and started hacking stuff away until I got to the single thing that produces the exception. One of the last things I did (ofcourse) was remove a little method tucked away in my Components class. Something I didnt realise the serializer would be looking at.

     

     

    ComponentManager -> Components -> List<BaseComponent : INotifyPropertyChanged>

     

     

    Turns out that the following where T : rule was to blame

     

    public T GetComponent<T>() where T : BaseComponent
    {

    }

     

    Of course in my repro I had forgotten to affix the 'where T : BaseComponent'

     

     

    So in conclusion the cause of this exception:

     

    "You must add a reference to assembly 'System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.

     

    is affixing 'where T : BaseComponent' to a method in the serializing class.

     

     

     

    I appreciate the XmlSerializer pipeline must be complex and in general it is a fantastic tool especially when combined with XSD but this really has to be tested properly for the next version and sensible levels of information must be presented to the developer when it dies.

     

    If you would like the repro project I can send it to you.

     

     

    Many thanks,

    Tom Deloford

     


     

     

     

     

     

    Friday, February 01, 2008 10:22 PM

All replies

  • I'm afraid the bug is in your project. You need to do what the exception said - you need to reference System.dll.

     

    Thursday, January 31, 2008 4:57 PM
    Moderator
  • Thanks John, I know I didnt supply much extra information but with all due repsect how likely do you think it is that my code builds with no reference to System?

     

    This exception comes from within XmlSerializer. A google finds people with this problem too, but it is related to Xml Web Services, I believe there is a hotfix out for it.

     

     

    But you are correct in a sense that is something to do with my project, I have created a repro, but it does not happen in the repro.

     

    Essentially my class structure is this

     

    ComponentManager ->* Component : BaseComponent : INotifyPropertChanged

     

    The ComponentManager is in a different project from the components and has a custom XmlRoot namespace attribute specified.

     

    When I call XmlSerialize on Component it works.

     

    When I call XmlSerialize on ComponentManager it fails

     

    everything references System and has a using System.ComponentModel for good measure!

     

    here is the stack trace..

     

       at System.Xml.Serialization.Compiler.Compile(Assembly parent, String ns, XmlSerializerCompilerParameters xmlParameters, Evidence evidence)
       at System.Xml.Serialization.TempAssembly.GenerateAssembly(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, Evidence evidence, XmlSerializerCompilerParameters parameters, Assembly assembly, Hashtable assemblies)
       at System.Xml.Serialization.TempAssembly..ctor(XmlMapping[] xmlMappings, Type[] types, String defaultNamespace, String location, Evidence evidence)
       at System.Xml.Serialization.XmlSerializer.GenerateTempAssembly(XmlMapping xmlMapping, Type type, String defaultNamespace)
       at System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultNamespace)
       at System.Xml.Serialization.XmlSerializer..ctor(Type type)
       at xxx.Core.Utils.Serializer.Serialize(Object objectToSerialise) in   (HAS REFERENCE TO SYSTEM)

     

    When I remove INotifyPropertChanged from BaseComponent it works.

     

    I have tried everything, any help greatly appreciated!

     

     

    Many Thanks,

    Tom

    Thursday, January 31, 2008 6:15 PM
  • I notice that INotifyPropertyChanged has an event. Is anyone subscribed to the event at the time you serialize?

    Thursday, January 31, 2008 6:44 PM
    Moderator
  • There are no subscribers to this event.

     

    Strange thing is it will serialize when I serialize the Component object directly but not when I serialize the parent ComponentManager (which contains a list of Components).

     

    It would appear to be something to do with the fact that XmlSerializer has to dynamically assemble some proxy class which references both of my projects ComponentManager.dll and Components.dll.

     

    So could it be a trust issue?? In my repro I do not have signing turned on, I will try that next.

    Thursday, January 31, 2008 8:47 PM
  • Ok, let's simplify things a bit. What happens if ComponentManager contains an array of Component instead of a list?

     

    Friday, February 01, 2008 2:52 AM
    Moderator
  • In fact I have a wrapper class called Components that provides better access to the List.

     

    So the structure is actually

     

         < ComponentManager.dll>                              <Components.dll>               <GAC>

    ComponentManager -> Components     ->    List<BaseComponent : INotifyPropertyChanged>

     

    I cant really change that to Array easily.

     

     

    Frustratingly I had to implement ReadXml and WriteXml to allow the Components object to serialize (why does XmlSerializer not support generic lists properly?)

     

    Unfortunately my dev machine has died today, but once its back I shall spend some time building up the complexity in my repro until I hit the problem. Hopefully then I will either find out I am being dumb or realise that this is a weakness in the XmlSerializer design and we can find a remedy.

     

     

    My guess is this issue might be similar to:

     

    http://www.thescripts.com/forum/thread178452.html

     

    when my computer is repaired (what the hell is a ram parity error anyway??) I am going to try to run the XmlSerializerPreCompiler tool to try and investigate.

     

     

    Cheers,

    Tom

    Friday, February 01, 2008 2:16 PM
  • RAM parity error means you have a failure in one of your memory chips.

     

    Parity is a method of error detection. You take some number of bits, let's say, 8. You count for each eight bits in your memory, count the number of bits set to 1. Now, for each eight bits, add a ninth bit, called the parity bit. Set the parity bit to 1 if the number of 1 bits is odd, set the parity bit to 0 if the number of one bits is even.

     

    Now, when you read memory, read the eight bits plus the parity bit. Do the parity calculation again. If your new calculation doesn't match the parity bit, you have lost one of the nine bits, and you report a parity error.

     

    Expensive memory arrays, like in a server, use a method called ECC, that allows for error detection and correction, at the cost of more "overhead" bits. They can correct single-bit errors, and detect double-bit errors. Parity won't detect if both a 1 bit becomes 0 and at the same time, a 0 bit becomes 1.

     

    Sorry for the lecture, but I once worked writing the code in an OS that handles when one of these errors is reported to the OS.

     

    Friday, February 01, 2008 2:26 PM
    Moderator
  • Ok, removed the chip and I'm limping along with 1.5gb RAM.

     

    Still geting the dodgy XmlSerializer exception though!

     

     

    Friday, February 01, 2008 3:51 PM
  • Yes, but at least you've proven that it's not an XmlSerializer problem that only happens with bad memory!

     

    Friday, February 01, 2008 7:30 PM
    Moderator
  • Success!

     

    I have found a reproducable new bug in XmlSerializer!

     

    No doubt this will turn out to be "by design" but nonetheless I am relieved to be able to move on with my project.

     

    How I found it

    So, I copied my entire project to another location and started hacking stuff away until I got to the single thing that produces the exception. One of the last things I did (ofcourse) was remove a little method tucked away in my Components class. Something I didnt realise the serializer would be looking at.

     

     

    ComponentManager -> Components -> List<BaseComponent : INotifyPropertyChanged>

     

     

    Turns out that the following where T : rule was to blame

     

    public T GetComponent<T>() where T : BaseComponent
    {

    }

     

    Of course in my repro I had forgotten to affix the 'where T : BaseComponent'

     

     

    So in conclusion the cause of this exception:

     

    "You must add a reference to assembly 'System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.

     

    is affixing 'where T : BaseComponent' to a method in the serializing class.

     

     

     

    I appreciate the XmlSerializer pipeline must be complex and in general it is a fantastic tool especially when combined with XSD but this really has to be tested properly for the next version and sensible levels of information must be presented to the developer when it dies.

     

    If you would like the repro project I can send it to you.

     

     

    Many thanks,

    Tom Deloford

     


     

     

     

     

     

    Friday, February 01, 2008 10:22 PM
  • Tom, I'm glad you found the problem.

     

    So, would is BaseComponent  in the same assembly? Maybe it really meant, "I can't find BaseComponent" and just screwed up the exception message?

     

    Either way, you should report this on Connect.

    Saturday, February 02, 2008 1:17 AM
    Moderator
  • The different assembly thing was a red herring.

     

    In the repro I moved everything to the same assembly. This is a bug, at a guess related to the order in which the serializer collects references for the temporary class. I changed the constrait to where T : class and it works.

     

    If I get time I will report it, but as it has cost me more than a day thats unlikely in the near future.

     

    Tom

    Saturday, February 02, 2008 5:33 PM
  • Tom, even if you only create a brief entry with a URL pointing to this thread, you will have increased the chances of this bug being fixed.

     

     

    Saturday, February 02, 2008 5:36 PM
    Moderator
  • I know this post is 3 years old, but I have reproduced the same error in VS2010 SP1 .NET 4.

     

    I've reported it to Connect at the following link:

    https://connect.microsoft.com/VisualStudio/feedback/details/668950/error-creating-xml-serializer-in-specific-situation-in-vb#

    Tuesday, May 17, 2011 7:20 PM