views:

339

answers:

2

I have WCF endpoint exposed as defined bellow,

<service name="MyApp.Server.Endpoint.Orange" behaviorConfiguration="MyTio.Server.Endpoint.OrangeBehavior">
  <endpoint address="" binding="basicHttpBinding" contract="Host.Server.Contract.IMyAppApi" bindingNamespace="http://host.com/myapp"&gt;
    <identity>
      <dns value="localhost"/>
    </identity>
  </endpoint>
  <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>

when I add a "Service Refrence" in .NET 3.5 we get the following class in the proxy which is perfectly fine:

    [System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="GetMemberBillersRequest", Namespace="http://schemas.datacontract.org/2004/07/Contract.MemberBillers")]
[System.SerializableAttribute()]
public partial class GetMemberBillersRequest : WCFClient.MyRequest {

    [System.Runtime.Serialization.OptionalFieldAttribute()]
    private int ApplicationIdField;

    [System.Runtime.Serialization.OptionalFieldAttribute()]
    private int ProductIdField;

    [System.Runtime.Serialization.DataMemberAttribute()]
    public int ApplicationId {
        get {
            return this.ApplicationIdField;
        }
        set {
            if ((this.ApplicationIdField.Equals(value) != true)) {
                this.ApplicationIdField = value;
                this.RaisePropertyChanged("ApplicationId");
            }
        }
    }

    [System.Runtime.Serialization.DataMemberAttribute()]
    public int ProductId {
        get {
            return this.ProductIdField;
        }
        set {
            if ((this.ProductIdField.Equals(value) != true)) {
                this.ProductIdField = value;
                this.RaisePropertyChanged("ProductId");
            }
        }
    }
}

the issue is when you add the reference to the same service but in .NET 2.0

you get the following proxy for the same contract:

    [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://schemas.datacontract.org/2004/07/Contract.MemberBillers")]
public partial class GetMemberBillersRequest : MyRequest {

    private int applicationIdField;

    private bool applicationIdFieldSpecified;

    private int productIdField;

    private bool productIdFieldSpecified;

    /// <remarks/>
    public int ApplicationId {
        get {
            return this.applicationIdField;
        }
        set {
            this.applicationIdField = value;
        }
    }

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

    /// <remarks/>
    public int ProductId {
        get {
            return this.productIdField;
        }
        set {
            this.productIdField = value;
        }
    }

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

both are identical except the proxy generated through .NET 2.0 has two additional fields:

productIdFieldSpecified and applicationIdFieldSpecified. the issue with these two fields are that if you don't set the them manually to true their corresponding fields (ApplicationId, ProductId ) will not be serialized and passed to the server!

can someone please explain to me what is happening here?

EDIT:

I have found that this is only happening for int types, not strings! here is the data contract for this operation

[DataContract]
public class GetMemberBillersRequest : MyRequest
{
    [DataMember]
    public int ApplicationId { get; set; }

    [DataMember]
    public int ProductId { get; set; }
}
+1  A: 

It would be helpful to see your service code. I haven't used web service reference for a while but my guess is that if those fields are not optional add a IsRequired = True to your DataMemeber attribute and regenrate the proxy.

Pratik
+1  A: 

This is the expected behavior, and has been that way since .NET 1.0. You'll see that for any primitive type which is optional in the schema - either an attribute with use="optional", or an element with minOccurs="0".

If the attribute or element were missing, then the generated property cannot be set to null. Instead, the *specified field is set to false in that case. Check that field before you decide whether the "real" one is present or not.

Similarly, if you want to set the main property, then you have to set the *specified property to true, otherwise it won't get sent.


I'm sure you know, but I'm adding this for future readers: Yes, there are nullable types now. However, development on ASMX web services slowed down considerably with the advent of WCF. It does not surprise me that nullable properties were never implemented for primitive types.

Also, be aware of this: Microsoft: ASMX Web Services are a “Legacy Technology”.

John Saunders
There are quite a few operation contract in this service, all with their own data-contract which are very similar (Just different names) none of them get the additional field. its only this contract and these two fields!
Keivan
I have no idea. I'd have to see the corresponding part of the XML Schema, and maybe the WSDL. Note that there's no doubt about my interpretation of the *specified fields, the only question may be why in one case but not another.
John Saunders
actually it is happening for all int types, even in other contracts too.
Keivan
It should happen for all non-nullable value types. Try setting one to [DataMember(Required=true)], and one to Nullable<int> and see what happens to each.
John Saunders
I have already tried [DataMember(Required=true)] which fixes the problem, now what to do with the fields that aren't technically required?
Keivan
Leave them as-is. Why do you say there's a "problem"? This is the way it's meant to be.
John Saunders