DefaultValue and XmlSerializer Don't Mix?

CraigBlog

Syndication

Maybe someone can explain to me why this:

using System;
using System.Xml.Serialization;

public class Foo {
  [XmlAttribute]
  [System.ComponentModel.DefaultValueAttribute("three")]
  public string value = "three";
}

public class App {
  public static void Main() {
    XmlSerializer ser = new XmlSerializer(typeof(Foo));
    Foo foo = new Foo();
    ser.Serialize(Console.Out, foo);
  }
}

produces this:

  <Foo />

whereas if you remove the DefaultValue attribute, you get this:

  <Foo value=”three” />

which is what I would expect. This is particularly troubling, since wsdl.exe will generate proxies that use System.ComponentModel.DefaultValueAttribute when it sees schema types with fixed value constraints.

I have to assume this is a bug in System.Xml.Serialization, but I'm willing to believe that there's some subtlety I've missed. I've confirmed this behavior in CLR 1.1 and 2.0.40607.


Posted Jul 27 2004, 08:15 PM by craig-andera

Comments

Kevin Dente wrote re: DefaultValue and XmlSerializer Don't Mix?
on 07-27-2004 7:56 PM
I too encountered this. Don't know if it should be classified as a bug or just as a peculiar decision by the XmlSerializer team. Basically, the serializer checks if the current value is equal to the default value, and if it is it doesn't bother including it in the serialized XML. Presumably the assumption is whoever is consuming the XML on the "other side" already knows the default value and will simply use that when it encounters the missing value (for example, by initializing it in an object just as you did). It's kind of like the way a server control only persist a property's value in markup if the value is different from the default value.

This approach probably made more sense back in the "object to XML to object" days of the original ASMX model. Both the server-side object and the client-side proxy know the default value, so by not sending it there's a small performance gain.

At least that's my guess for why it behaves that way. In any event, it makes a lot less sense in the "XML document exchange" model that is the current thinking for web services. Perhaps you can include this as a "customer ask" on Don Box's wiki. :)

Gerke Geurts wrote re: DefaultValue and XmlSerializer Don't Mix?
on 07-28-2004 12:33 AM
This is behaviour by design. If a XML schema defines a default value, the instance documents do not have to specify the value. When the XML document is accessed using a schema aware XML parser you should get the default value back.

See Microsoft support document <a href="http://support.microsoft.com/default.aspx?scid=kb;en-us;325691">Q325691</a>.

And a <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemxmlserializationxmlattributesclassxmldefaultvaluetopic.asp">quote from MSDN</a>:
<blockquote>
"If the value assigned to a field or property is equal to the default value for that field or property, the XmlSerializer will not serialize the value to the XML-instance. This is because the assigned value can be recovered from the XML schema."
</blockquote>
Craig wrote re: DefaultValue and XmlSerializer Don't Mix?
on 07-28-2004 4:23 AM
OK, thanks guys, that makes more sense. I'm not sure whether I agree with their decision or not, but at least I understand the issue.
Kevin Dente wrote re: DefaultValue and XmlSerializer Don't Mix?
on 07-28-2004 5:52 AM
On the bright side, according to that KB article:
"Microsoft plans to change this behavior in the next major version release of the .NET Framework."
Ian Griffiths wrote re: DefaultValue and XmlSerializer Don't Mix?
on 08-01-2004 10:54 AM
This is wholly consistent with the way that the DefaultValue attribute is used by the design-time serialization engine in VS.NET. (The oft-ignored third serialization mechanism in .NET...)

I wasn't aware that DefaultValue was used anywhere else actually, but in the world of Design Time, it has *always* meant "If this property has this value, you don't need to bother serializing it."

I'm slightly surprised to see it being used in the XML Serialization mechanism, but it is actually a pretty good match for the standard 'default value' semantics in XSD as someone already mentioned, so I suppose it does actually make sense. It's just that I always thought of this as being a part of the design time architecture.

I'm not sure why you find the behaviour surprising - the behaviour you say you were expecting doesn't make any more sense to me. Indeed there are situations where it would the wrong thing - in certain design-time scenarios, there is a difference between explicitly setting a value to its default and leaving to be its default. (E.g. with the Windows Forms Control class, setting the BackColor property turns off the ambient behaviour for that property.)

(Of course this means that if you specify [DefaultValue..] without actually making sure that the property/field really does have the default you say it will, it won't work properly.)
Craig wrote re: DefaultValue and XmlSerializer Don't Mix?
on 08-01-2004 11:30 AM
There are two reasons I find it surprising, although I now understand why it works the way it does.

1) To cross namespaces like that (i.e. an attribute from System.ComponentModel controlling the way System.Xml.Serialization works) seems dirty. This is purely aesthetic, of course, but part of good API design is not catching people off guard.

2) I found it surprising because the somewhat subtle behavior incorrect behavior you rightly point out is exactly that...somewhat subtle. "Default value" has a semantic that to most people means, "If I don't do anything, otherwise, it should have *this* value."

The latter point is, of course, a deficiency in my understanding. However, I highly doubt I'd be the only one (or even in the minority) when it comes to being caught off guard by the semanitcs here. Hence the post. ;)

The real issue here is that the semantics of having a fixed default value in an XSD is just weird. It means that if I give you an instance document, you have to go look at the *schema* to figure out what the value of that attribute should be. That's just wrong.
Ivan Towlson wrote re: DefaultValue and XmlSerializer Don't Mix?
on 08-02-2004 12:18 AM
But, if the contract *can* be clearly communicated -- and I take your point, Craig, about the dangers of expecting the client to go check a schema -- it *is* a valuable option to have around. We had a performance issue with one Web service where the response message contained date/times. Most of these values were effectively "null" (i.e. no time applicable), and serialising those values was taking up a lot of time and bandwidth. Using DefaultValue to serialise only non-"null" times measurably (indeed significantly) improved the performance of the service.
Craig wrote re: DefaultValue and XmlSerializer Don't Mix?
on 08-02-2004 4:51 AM
Actually, I'd say what you're running into is the mismatch between objects (where DateTime can't be null) and XML (where an element can either appear with a datetime value or not). Nothing to do with XSD's fixed value semantics.

I agree that it's nice to have the ability to do what you want (and you can do it without DefaultValue if you're willing to handle the XML yourself (which is pretty easy)) but I dislike the way it's implemented.
Dino Chiesa wrote re: DefaultValue and XmlSerializer Don't Mix?
on 08-04-2004 3:29 AM
There is a xxxSpecified mechanism that allows you to do the same thing - only serialize a field/property when you want to serialize it, when it holds a meaningful value.

http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemXmlSerializationXmlIgnoreAttributeClassTopic.asp

CraigBlog wrote Coalesce
on 08-04-2004 2:18 PM
Martin Brown wrote re: DefaultValue and XmlSerializer Don't Mix?
on 08-18-2004 5:40 AM
I have a class defined as:

[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://tempuri.org/XMLSchema1.xsd"">http://tempuri.org/XMLSchema1.xsd"">http://tempuri.org/XMLSchema1.xsd"">http://tempuri.org/XMLSchema1.xsd")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="http://tempuri.org/XMLSchema1.xsd"">http://tempuri.org/XMLSchema1.xsd"">http://tempuri.org/XMLSchema1.xsd"">http://tempuri.org/XMLSchema1.xsd", IsNullable=false)]
public class MartinTest {

/// <remarks/>
[System.ComponentModel.DefaultValueAttribute(false)]
public bool tstBool = false;
}

When I serialize this I just get:

<?xml version="1.0" encoding="utf-16"?>
<MartinTest xmlns:xsd="http://www.w3.org/2001/XMLSchema"">http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"">http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/XMLSchema1.xsd"">http://tempuri.org/XMLSchema1.xsd"">http://tempuri.org/XMLSchema1.xsd"">http://tempuri.org/XMLSchema1.xsd" />

When I validate this against the schema using XMLSpy I get a validation error message. If however I change it to the following it validates fine:

<?xml version="1.0" encoding="utf-16"?>
<MartinTest xmlns:xsd="http://www.w3.org/2001/XMLSchema"">http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"">http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/XMLSchema1.xsd"">http://tempuri.org/XMLSchema1.xsd"">http://tempuri.org/XMLSchema1.xsd"">http://tempuri.org/XMLSchema1.xsd">
<tstBool />
</MartinTest>

Does anyone know how to get the serializer to produce xml formatted like this?
Martin Brown wrote re: DefaultValue and XmlSerializer Don't Mix?
on 08-18-2004 5:50 AM
The formating of my last post seems to have gone a bit mad. For some reason the namespaces have been repeated.
Craig wrote re: DefaultValue and XmlSerializer Don't Mix?
on 08-18-2004 6:38 AM
FWIW, I belive it's XMLSpy that's wrong, and not XmlSerializer.

But XSD defaults are evil, and you should avoid them if you can.
Martin Brown wrote re: DefaultValue and XmlSerializer Don't Mix?
on 08-19-2004 1:29 AM
I think this was my fault. In the schema I had set both the default="false" and minOccurs="1". I guess these two settings conflict.
Craig wrote re: DefaultValue and XmlSerializer Don't Mix?
on 08-19-2004 6:29 AM
Yep, that would make sense, since the XSD meaning of default="false" is that the value is always "false", and should never actually appear in the document. Whereas minOccurs="1" indicates that it *must* appear in the document.

Hence my argument that XSD default sucks: it means that in order to know what the XML actually contains, you have to look at both the instance document and the schema. Blech.
ben kloosterman wrote re: DefaultValue and XmlSerializer Don't Mix?
on 12-23-2004 3:48 PM
This is a very important feature which allows you to only send data you need over the wire.

When a Web client/proxy recreates the object it will be recreated witht he data which the client can then change.

Used well and it will half your traffic.

Ben
:-$ wrote XmlSerializer eats default attributes
on 10-17-2005 12:09 PM

Add a Comment

(required)  
(optional)
(required)  
Remember Me?