Tuesday, January 17, 2012

WCF IsRequired Attribute

For a customer we are developing some WCF webservices. Our message contracts are defined by using  DataContract and DataMember attributes on top of our classes and their properties.
The DataMember attribute has some extra properties that allows us to add some extra rules. For example if a property should always be available, we use (IsRequired=true); to indicate this. These rules are checked when a message is received or send.
[DataContract]
public class TestClass
{
        [DataMember(IsRequired = true)]
        public string RequiredValue { get; set; }
}


However during our test we noticed that it doesn’t work.


What’s confusing here is that a DataMember has (EmitDefaultValue=true) set by default. An string property’s value starts as String.Empty.


Turn this off by using (EmitDefaultValue=false). Now, a property’s value is null, letting (IsRequired=true) do its validation work as desired.


[DataContract]
public class TestClass
{
        [DataMember(IsRequired = true, EmitDefaultValue=false)]
        public string RequiredValue { get; set; }
}


Although it’s still not what we expected. If we add a not-required property(e.g. NotRequiredValue) that refers to a class(e.g. ChildClass) that has a required property(e.g. RequiredValue) the validation fails saying that the RequiredValue is missing. Anyone who has a solution?


[DataContract]
public class TestClass
{
        [DataMember(IsRequired = true)]
        public string RequiredValue { get; set; }
  
  [DataMember(IsRequired = false)]
  public ChildClass NotRequiredValue { get;set; }
}

[DataContract]
public class ChildClass
{
        [DataMember(IsRequired = true)]
        public string RequiredValue { get; set; }
}

2 comments:

Biff Gaut said...

I believe the issue is the difference between the XML on the wire and the .NET objects.

IsRequired pertains to the XML, so the tag must be there - but it can be empty. What this means is that what comes over the wire when IsRequired is TRUE can be-





but it cannot be




The second example would be allowed if IsRequired were FALSE or not specified. If you are writing a .NET client and never dealing with the XML directly you will have this level of detail abstracted away. If you use a SOAP client such as SOAPui to test your service you will probably be able to demonstrate this.

Biff Gaut said...

(Reposting as my XML was HTML-ified in my previous post)

I believe the issue is the difference between the XML on the wire and the .NET objects.

IsRequired pertains to the XML, so the tag must be there - but it can be empty. What this means is that what comes over the wire when IsRequired is TRUE can be-

<TestClass>
<RequiredValue></RequiredValue>
</TestClass>

but it cannot be

<TestClass>
</TestClass>

The second example would be allowed if IsRequired were FALSE or not specified. If you are writing a .NET client and never dealing with the XML directly you will have this level of detail abstracted away. If you use a SOAP client such as SOAPui to test your service you will probably be able to demonstrate this.