views:

1856

answers:

2

I've seen quite a few posts on changes in .NET 3.5 SP1, but stumbled into one that I've yet to see documentation for yesterday. I had code working just fine on my machine, from VS, msbuild command line, everything, but it failed on the build server (running .NET 3.5 RTM).

[XmlRoot("foo")]
public class Foo
{
    static void Main()
    {
        XmlSerializer serializer = new XmlSerializer(typeof(Foo));

        string xml = @"<foo name='ack' />";
        using (StringReader sr = new StringReader(xml))
        {
            Foo foo = serializer.Deserialize(sr) as Foo;
        }
    }

    [XmlAttribute("name")]
    public string Name { get; set; }

    public Foo Bar { get; private set; }
}

In SP1, the above code runs just fine. In RTM, you get an InvalidOperationException:

Unable to generate a temporary class (result=1). error CS0200: Property or indexer 'ConsoleApplication2.Foo.Bar' cannot be assign to -- it is read only

Of course, all that's needed to make it run under RTM is adding [XmlIgnore] to the Bar property.

My google fu is apparently not up to finding documentation of these kinds of changes. Is there a change list anywhere that lists this change (and similar under-the-hood changes that might jump up and shout "gotcha")? Is this a bug or a feature?

EDIT: In SP1, if I added a <Bar /> element, or set [XmlElement] for the Bar property, it won't get deserialized. It doesn't fail pre-SP1 when it tries to deserialize--it throws an exception when the XmlSerializer is constructed.

This makes me lean more toward it being a bug, especially if I set an [XmlElement] attribute for Foo.Bar. If it's unable to do what I ask it to do, it should be throwing an exception instead of silently ignoring Foo.Bar. Other invalid combinations/settings of XML serialization attributes result in an exception.

EDIT: Thank you, TonyB, I'd not known about setting the temp files location. For those that come across similar issues in the future, you do need an additional config flag:

<system.diagnostics>
  <switches>
    <add name="XmlSerialization.Compilation" value="1" />
  </switches>
</system.diagnostics>
<system.xml.serialization>
  <xmlSerializer tempFilesLocation="c:\\foo"/>
</system.xml.serialization>

Even with setting an [XmlElement] attribute on the Bar property, no mention was made of it in the generated serialization assembly--which fairly firmly puts this in the realm of a silently swallowed error (aka, a bug). Either that or the designers have decided [XmlIgnore] is no longer necessary for properties that can't be set--and you'd expect to see that in release notes, change lists, or the XmlIgnoreAttribute documentation.

+1  A: 

In SP1 does the foo.Bar property get properly deserialized?

In pre SP1 you wouldn't be able to deserialize the object because the set method of the Bar property is private so the XmlSerializer doesn't have a way to set that value. I'm not sure how SP1 is pulling it off.

You could try adding this to your web.config/app.config

<system.xml.serialization> 
  <xmlSerializer tempFilesLocation="c:\\foo"/> 
</system.xml.serialization>

That will put the class generated by the XmlSerializer into c:\foo so you can see what it is doing in SP1 vs RTM

TonyB
A: 

I rather like this new (?) behavior because the XML document doesn't have any mention of Bar in it, so the deserializer should not even be attempting to set it.

Jesse C. Slicer