Why does adding an enum parameter to an operation cause the proxy to explode into message contracts?

This was a question asking why the following perfectly ordinary operation contract caused svcutil.exe to spit out some really ugly code.

[OperationContract]
void Foo(EnumType e);

Getting started debugging the problem was fairly easy because svcutil left a nice comment explaining what went wrong during code generation.

// CODEGEN: Generating message contract since element name e from namespace http://tempuri.org/ is not marked nillable

This was a completely accurate statement because when I checked the schema for the operation, the operation parameter was not marked nillable. However, it didn't help at all to explain why this was happening.

<xs:element name="Foo">
<xs:complexType>
<xs:sequence>
<xs:element xmlns:q1="http://schemas.datacontract.org/2004/07/" minOccurs="0" name="e" type="q1:EnumType" />
</xs:sequence>
</xs:complexType>
</xs:element>

A brutal way to solve the problem would be to change the operation parameter from EnumType to EnumType? to force it to be nillable. Clearly though, something more fundamental was wrong because when I checked the schema for EnumType it was not what I expected.

<xs:simpleType name="EnumType">
<xs:restriction base="xs:string" />
</xs:simpleType>

The error wasn't that EnumType was passed as a string (it's relatively common to represent an enumeration using the names of the values), but that the type didn't actually define any values at all. I would have expected to see under the restriction a list of enumeration values for this type. This was also apparent in the generated proxy. The proxy was using raw strings rather than a nice enumerated type because the restriction had no values defined.

The problem was solved by looking at the definition of EnumType.

[DataContract]
public enum EnumType { ValueOne, ValueTwo }

By applying a DataContract attribute, the default serialization contract for the enum was replaced by a contract that didn't include any of the values as members. The default contract would have included all of the values. Specifying a DataContract attribute is only needed when customizing the serialization contract, such as when you only want to expose a subset of the enumeration values. Removing the spurious DataContract attribute fixed the schema problems and allowed svcutil to generate proxies with a nice enumeration type.

Next time: Augmenting Security Requests