Search code examples
c#.netwcf

WCF service proxy not setting "FieldSpecified" property


I've got a WCF DataContract that looks like the following:

namespace MyCompanyName.Services.Wcf
{
  [DataContract(Namespace = "http://mycompanyname/services/wcf")]
  [Serializable]
  public class DataContractBase
  {
    [DataMember]
    public DateTime EditDate { get; set; }

    // code omitted for brevity...
  }
}

When I add a reference to this service in Visual Studio, this proxy code is generated:

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "2.0.50727.3082")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://mycompanyname/services/wcf")]
public partial class DataContractBase : object, System.ComponentModel.INotifyPropertyChanged {

    private System.DateTime editDateField;

    private bool editDateFieldSpecified;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Order=0)]
    public System.DateTime EditDate {
        get {
            return this.editDateField;
        }
        set {
            this.editDateField = value;
            this.RaisePropertyChanged("EditDate");
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlIgnoreAttribute()]
    public bool EditDateSpecified {
        get {
            return this.editDateFieldSpecified;
        }
        set {
            this.editDateFieldSpecified = value;
            this.RaisePropertyChanged("EditDateSpecified");
        }
    }

    // code omitted for brevity...
}

As you can see, besides generating a backing property for EditDate, an additional <propertyname>Specified property is generated. All good, except that when I do the following:

DataContractBase myDataContract = new DataContractBase();
myDataContract.EditDate = DateTime.Now;

new MyServiceClient.Update(new UpdateRequest(myDataContract));

the EditDate was not getting picked up by the endpoint of the service (does not appear in the transmitted XML).

I debugged the code and found that, although I was setting EditDate, the EditDateSpecified property wasn't being set to true as I would expect; hence, the XML serializer was ignoring the value of EditDate, even though it's set to a valid value.

As a quick hack I modified the EditDate property to look like the following:

   /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Order=0)]
    public System.DateTime EditDate {
        get {
            return this.editDateField;
        }
        set {
            this.editDateField = value;

            // hackhackhack
            if (value != default(System.DateTime))
            {
              this.EditDateSpecified = true;
            }
            // end hackhackhack

            this.RaisePropertyChanged("EditDate");
        }
    }

Now the code works as expected, but of course every time I re-generate the proxy, my modifications are lost. I could change the calling code to the following:

DataContractBase myDataContract = new DataContractBase();
myDataContract.EditDate = DateTime.Now;
myDataContract.EditDateSpecified = true;

new MyServiceClient.Update(new UpdateRequest(myDataContract));

but that also seems like a hack-ish waste of time.

So finally, my question: does anyone have a suggestion on how to get past this unintuitive (and IMO broken) behavior of the Visual Studio service proxy generator, or am I simply missing something?


Solution

  • It might be a bit unintuitive (and caught me off guard and reeling, too!) - but it's the only proper way to handle elements that might or might not be specified in your XML schema.

    And it also might seem counter-intuitive that you have to set the xyzSpecified flag yourself - but ultimately, this gives you more control, and WCF is all about the Four Tenets of SOA of being very explicit and clear about your intentions.

    So basically - that's the way it is, get used to it :-) There's no way "past" this behavior - it's the way the WCF system was designed, and for good reason, too.

    What you always can do is catch and handle the this.RaisePropertyChanged("EditDate"); event and set the EditDateSpecified flag in an event handler for that event.