WCF Rest Datamember and Array issue - c#

I've created a WCF service and the service is receiving the XML structure with all the data but the PackageID and ServiceCode. The problem seems to be in public RequestPackages[] Packages in the Track class.
If I change it to RequestPackages in the code below then the element data will be passed into the service method and will show in the PackageID/ServiceCode elements.
If I have it as RequestPackages[] then I get this stepping through in debug in the xml for Packages Element: wcf.RequestPackages[0] and PackageID/ServiceCode are not available. I am stepping through debug to view xml data passed as it hits the service method. I'm not sure how to resolve it but I've probably overlooked something simple. Thanks
Below is the Xml structure being sent:
<Track>
<Packages>
<PackageId>1234567890</PackageId>
<ServiceCode>123</ServiceCode>
</Packages>
</Track>
Below is the Data contracts:
[DataContract(Namespace = "")]
[XmlArrayItemAttribute("Package")]
public partial class Track
{
private RequestPackages[] packagesField;
/// <remarks/>
[DataMember(Order=0, Name="Package")]
public RequestPackages[] Packages
{
get
{
return this.packagesField;
}
set
{
this.packagesField = value;
}
}
}
[DataContract(Namespace = "")]
[XmlSerializerFormat]
public partial class RequestPackages
{
private string packageIdField;
private string serviceCodeField;
/// <remarks/>
[DataMember(Order = 0)]
[XmlElementAttribute]
public string PackageId
{
get
{
return this.packageIdField;
}
set
{
this.packageIdField = value;
}
}
/// <remarks/>
[DataMember(Order=1)]
[XmlElementAttribute]
public string ServiceCode
{
get
{
return this.serviceCodeField;
}
set
{
this.serviceCodeField = value;
}
}
}

I was missing an element in the xml...
<Packages>
<RequestPackages>
<PackageId>1234567890</PackageId>
<ServiceCode></ServiceCode>
</RequestPackages>
</Packages>

Related

Deserialize the soap xml response in a .netcore app

I have to call a soap service from a C# .net core app and get the results in a class that I can use to do some logic. I did the soap request and the remote call works fine, but now I have to deserialize the xml soap response into a class. Here's an example of the response:
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://some_domain/soap/ApplicationServices">
<SOAP-ENV:Body>
<ns1:preparelabelsResponse xmlns:ns1="http://some_domain/soap/ApplicationServices">
<return xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="tns:PrepareReturn[1]">
<item xsi:type="tns:PrepareReturn">
<clientref xsi:type="xsd:string">2015/0418/001</clientref>
<pclid xsi:type="xsd:string"></pclid>
<error xsi:type="xsd:string">Invalid timestamp 20191018105727</error>
</item>
</return>
</ns1:preparelabelsResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Since I'm using Visual Studio 2017 I tried adding a connected service in my .netcore app using the WCF Web Service Reference Provider and then call the method. The call failed with the message: Wrong XML format, that was probably generated by the server. Doing the same steps in a .net framework app worked fine though, and I got the proper response. So I suspect something is different in the .netcore wcf provider.
My second approach was to create the soap request manually and then parse the soap response. For constructing the request I have an elegant solution, but for parsing the response I don't. I tried to use the classes that were generated by the wcf provider, but the xml deserialization didn't work. I then tried to change the attributes to get it right, but didn't help. I added below those classes:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("dotnet-svcutil", "1.0.0.1")]
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
[System.ServiceModel.MessageContractAttribute(WrapperName="preparelabelsResponse", WrapperNamespace="encoded", IsWrapped=true)]
public partial class preparelabelsResponse
{
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="", Order=0)]
public PrepareReturn[] #return;
public preparelabelsResponse()
{
}
public preparelabelsResponse(PrepareReturn[] #return)
{
this.#return = #return;
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("dotnet-svcutil", "1.0.0.1")]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.Xml.Serialization.SoapTypeAttribute(Namespace="http://some_domain/soap/ApplicationServices")]
public partial class PrepareReturn
{
private string clientrefField;
private string pclidField;
private string errorField;
/// <remarks/>
public string clientref
{
get
{
return this.clientrefField;
}
set
{
this.clientrefField = value;
}
}
/// <remarks/>
public string pclid
{
get
{
return this.pclidField;
}
set
{
this.pclidField = value;
}
}
/// <remarks/>
public string error
{
get
{
return this.errorField;
}
set
{
this.errorField = value;
}
}
}
And the xml deserialization:
var soapResponse = XDocument.Load(sr);
XNamespace myns = "http://some_domain/soap/ApplicationServices";
var xml = soapResponse.Descendants(myns + "preparelabelsResponse").FirstOrDefault().ToString();
var result = Deserialize<preparelabelsResponse>(xml);
...
public static T Deserialize<T>(string xmlStr)
{
var serializer = new XmlSerializer(typeof(T));
T result;
using (TextReader reader = new StringReader(xmlStr))
{
result = (T)serializer.Deserialize(reader);
}
return result;
}
So what I could do is to strip the xml away of all the namespaces and attributes and deserialize it to a simple class, but that is not an elegant solution for my problem. What I want is to be able to create/decorate my classes in such a way that the deserialization will work without any altering of the actual xml contents.

Deserializing complicated xml into objects - Problems creating the objects

Ok so I am working on deserializing an xml document into objects.
Basically my xml document will look like this:
<?xml version="1.0"?>
<root>
<eConnect CUSTNMBR="22222" DATE1="1900-01-01T00:00:00" TABLENAME="RM00101" DBNAME="BOLT" Requester_DOCTYPE="Customer" ACTION="0">
<Customer>
<CUSTNMBR>22222</CUSTNMBR>
<ADDRESS1>123 ABC St</ADDRESS1>
<ADDRESS2/>
<ADDRESS3/>
<ADRSCODE>PRIMARY</ADRSCODE>
<CITY>Ann Arbor</CITY>
<CNTCPRSN/>
<COUNTRY>USA</COUNTRY>
<CPRCSTNM/>
<CURNCYID/>
<CUSTCLAS/>
<CUSTDISC>0</CUSTDISC>
<CUSTNAME>Test Customer 2</CUSTNAME>
<PHONE1>4165551234</PHONE1>
<PHONE2/>
<PHONE3/>
<FAX/>
<PYMTRMID/>
<SALSTERR/>
<SHIPMTHD/>
<SLPRSNID/>
<STATE>Micigan</STATE>
<TAXSCHID/>
<TXRGNNUM/>
<UPSZONE/>
<ZIP>45612</ZIP>
<STMTNAME>Test Customer 2</STMTNAME>
<SHRTNAME>Test Customer 2</SHRTNAME>
<PRBTADCD>PRIMARY</PRBTADCD>
<PRSTADCD>PRIMARY</PRSTADCD>
<STADDRCD>PRIMARY</STADDRCD>
<CHEKBKID/>
<CRLMTTYP>0</CRLMTTYP>
<CRLMTAMT>0.00000</CRLMTAMT>
<CRLMTPER>0</CRLMTPER>
<CRLMTPAM>0.00000</CRLMTPAM>
<RATETPID/>
<PRCLEVEL/>
<MINPYTYP>0</MINPYTYP>
<MINPYDLR>0.00000</MINPYDLR>
<MINPYPCT>0</MINPYPCT>
<FNCHATYP>0</FNCHATYP>
<FNCHPCNT>0</FNCHPCNT>
<FINCHDLR>0.00000</FINCHDLR>
<MXWOFTYP>0</MXWOFTYP>
<MXWROFAM>0.00000</MXWROFAM>
<COMMENT1>test comment</COMMENT1>
<COMMENT2>another test</COMMENT2>
<USERDEF1/>
<USERDEF2/>
<TAXEXMT1/>
<TAXEXMT2/>
<BALNCTYP>0</BALNCTYP>
<STMTCYCL>5</STMTCYCL>
<BANKNAME/>
<BNKBRNCH/>
<FRSTINDT>1900-01-01T00:00:00</FRSTINDT>
<INACTIVE>0</INACTIVE>
<HOLD>0</HOLD>
<CRCARDID/>
<CRCRDNUM/>
<CCRDXPDT>1900-01-01T00:00:00</CCRDXPDT>
<KPDSTHST>1</KPDSTHST>
<KPCALHST>1</KPCALHST>
<KPERHIST>1</KPERHIST>
<KPTRXHST>1</KPTRXHST>
<CREATDDT>2015-11-27T00:00:00</CREATDDT>
<MODIFDT>2015-11-27T00:00:00</MODIFDT>
<Revalue_Customer>1</Revalue_Customer>
<Post_Results_To>0</Post_Results_To>
<FINCHID/>
<GOVCRPID/>
<GOVINDID/>
<DISGRPER>0</DISGRPER>
<DUEGRPER>0</DUEGRPER>
<DOCFMTID/>
<Send_Email_Statements>0</Send_Email_Statements>
<GPSFOINTEGRATIONID/>
<INTEGRATIONSOURCE>0</INTEGRATIONSOURCE>
<INTEGRATIONID/>
<Address>
<CUSTNMBR>22222</CUSTNMBR>
<ADRSCODE>PRIMARY</ADRSCODE>
<SLPRSNID/>
<UPSZONE/>
<SHIPMTHD/>
<TAXSCHID/>
<CNTCPRSN/>
<ADDRESS1>123 ABC St</ADDRESS1>
<ADDRESS2/>
<ADDRESS3/>
<COUNTRY>USA</COUNTRY>
<CITY>Ann Arbor</CITY>
<STATE>Micigan</STATE>
<ZIP>45612</ZIP>
<PHONE1>4165551234</PHONE1>
<PHONE2/>
<PHONE3/>
<FAX/>
<GPSFOINTEGRATIONID/>
<INTEGRATIONSOURCE>0</INTEGRATIONSOURCE>
<INTEGRATIONID/>
<Internet_Address/>
</Address>
</Customer>
</eConnect>
</root>
When I try to deserialize this, I get an "Object reference not set to instance of an object" exception. My classes look like this:
[XmlRoot("root")]
public class eConnect
{
public Customer customer;
}
public class Customer
{
public string CUSTNMBR { get; set; }
public string CUSTNAME { get; set; }
}
Am I getting the exception because I have to have variables for all the nodes in the xml document? Is there a way to only use the nodes I need?
Also am I creating my classes the right way, because basically the xml will have a root node called root and the root can contain multiple eConnect nodes, but each eConnect node will only contain one customer node.
Try adding the Serializable attribute on your classes and using the XmlElement tag inside your classes to define how the objects are mapped. I would also make a separate class for your root.
[XmlRoot("root")]
[Serializable]
public class Root
{
public Root()
{
eConnects = new List<eConnect>();
}
[XmlElement("eConnect")]
public List<eConnect> eConnects { get; set; }
}
[XmlRoot("eConnect")]
[Serializable]
public class eConnect
{
[XmlElement("Customer")]
public Customer customer { get; set; }
}
[XmlRoot("Customer")]
[Serializable]
public class Customer
{
[XmlElement("CUSTNMBR")]
public string CUSTNMBR { get; set; }
[XmlElement("CUSTNAME")]
public string CUSTNAME { get; set; }
}
Using the XmlElement tag also gives you the freedom to name your variables friendlier names. For example you could switch
[XmlElement("CUSTNAME")]
public string CUSTNAME { get; set; }
to
[XmlElement("CUSTNAME")]
public string CustomerName { get; set; }
Use Visual Studio's Paste XML as Classes feature.
To do this: Open Visual Studio > Edit Menu > Paste Special > Paste XML as Classes.
The resulting classes may need clean up (e.g. change type from ushort to int etc.). This feature handles the necessary attributes for serialization. Here is an example for your xml:
/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class root
{
private rootEConnect eConnectField;
/// <remarks/>
public rootEConnect eConnect
{
get
{
return this.eConnectField;
}
set
{
this.eConnectField = value;
}
}
}
// Intermediate Xml nodes ...
/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class rootEConnectCustomer
{
private ushort cUSTNMBRField;
private string aDDRESS1Field;
private object aDDRESS2Field;
private object aDDRESS3Field;
private string aDRSCODEField;
// rest of class ...
}

Validating inherited attribute using DataAnnotations

I have MVC project that relies on webservices to provide data and those webservices are based on CMIS specification with custom functionality. I have several classes used as DataContracts, which were created by Visual Studio when I added references to services I am calling. I am using that class as a model to ensure I am able to send instances to the service and process correctly those sent back to me.
I also have views to edit instances of those classes and I would like to use DataAnnotations to validate the forms (usually [Required] atribute and sometimes display name change).
I do not want to put those atributes in service reference files because updating the reference would mean I will loose those atributes (at least I could not be sure everything is still the same after reference update).
My thought was to create child class that would only serve as tool to introduce DataAnnotations to atributes I know for sure I will be using (those that will not dissapear from DataContract class for sure). How would I accomplish such inheritance with code?
Example - I have this class created by VS in reference.cs file:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="LibraryRequest", Namespace="http://schemas.datacontract.org/2004/07/Agamemnon.Models")]
[System.SerializableAttribute()]
public partial class LibraryRequest : DocuLive.RepositoryServiceExt.Library {
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string PasswordField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string ServerField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private bool UseDefaultField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string UserNameField;
[System.Runtime.Serialization.DataMemberAttribute()]
public string Password {
get {
return this.PasswordField;
}
set {
if ((object.ReferenceEquals(this.PasswordField, value) != true)) {
this.PasswordField = value;
this.RaisePropertyChanged("Password");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string Server {
get {
return this.ServerField;
}
set {
if ((object.ReferenceEquals(this.ServerField, value) != true)) {
this.ServerField = value;
this.RaisePropertyChanged("Server");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public bool UseDefault {
get {
return this.UseDefaultField;
}
set {
if ((this.UseDefaultField.Equals(value) != true)) {
this.UseDefaultField = value;
this.RaisePropertyChanged("UseDefault");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string UserName {
get {
return this.UserNameField;
}
set {
if ((object.ReferenceEquals(this.UserNameField, value) != true)) {
this.UserNameField = value;
this.RaisePropertyChanged("UserName");
}
}
}
}
I want to make sure that no matter what changes in reference.cs file (even that class itself), I will always have Username, Password and Server marked as [Required] in my "Edit" and "Delete" forms.
Thanks in advance
Honza
I would stay away from inheriting an autogenerated class. It would not solve your problem with the attributes - you would have to override every single property so you can add attributes to it.
One solution is to use hand-coded datacontracts instead of autogenerated references. You will have full control over when they change, and you can put the attributes you need in them.
Another solution is wrapping the contract in your view model. Like this:
public class LibraryRequestViewModel {
private LibraryRequest request;
public LibraryRequestViewModel(LibraryRequest request){
this.request = request;
}
[Required]
public string Password {
get { return this.request.Password; }
set { this.request.Password = value; }
}
// do this for all fields you need
}

Deserializing XML where each object has a list of objects

I'm working on a WP7 app which gets and updates data on a web server. If any updates need a response, I get a list of errors that needs to be dealt with, and a list of possible choices for each error. The issue I'm having is assigning each object its appropriate list of choices. As of now I get a list of errors, and another list of all possible choices for all errors. I'd like the error object to contain the list of only its options so I can handle that.
So here's an example response:
<?xml version="1.0" encoding="utf-8"?>
<response xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<response_error_dialogs>
<error_dialog_list>
<error_dialog_choice>
<error_dialog_id>1301</error_dialog_id>
<error_dialog_message>You have changed the phone number. Select which phone number to make the primary contact number.</error_dialog_message>
<error_dialog_title>Phone Number Changed</error_dialog_title>
<error_dialog_is_set>false</error_dialog_is_set>
<error_dialog_choice_option_list>
<error_dialog_choice_option>
<error_dialog_choice_option_id>1</error_dialog_choice_option_id>
<error_dialog_choice_option_title>Home</error_dialog_choice_option_title>
</error_dialog_choice_option>
<error_dialog_choice_option>
<error_dialog_choice_option_id>2</error_dialog_choice_option_id>
<error_dialog_choice_option_title>Mobile</error_dialog_choice_option_title>
</error_dialog_choice_option>
<error_dialog_choice_option>
<error_dialog_choice_option_id>3</error_dialog_choice_option_id>
<error_dialog_choice_option_title>Work</error_dialog_choice_option_title>
</error_dialog_choice_option>
</error_dialog_choice_option_list>
</error_dialog_choice>
<error_dialog_choice>
<error_dialog_id>1303</error_dialog_id>
<error_dialog_message>You have changed the account email address. Would you like this to be the new default email?</error_dialog_message>
<error_dialog_title>Email Address Changed</error_dialog_title>
<error_dialog_is_set>false</error_dialog_is_set>
<error_dialog_choice_option_list>
<error_dialog_choice_option>
<error_dialog_choice_option_id>1</error_dialog_choice_option_id>
<error_dialog_choice_option_title>No</error_dialog_choice_option_title>
</error_dialog_choice_option>
<error_dialog_choice_option>
<error_dialog_choice_option_id>2</error_dialog_choice_option_id>
<error_dialog_choice_option_title>Yes</error_dialog_choice_option_title>
</error_dialog_choice_option>
</error_dialog_choice_option_list>
</error_dialog_choice>
</error_dialog_list>
</response_error_dialogs>
</response>
And here's the classes used:
public class ErrorDialog
{
XElement self;
public ErrorDialog() { }
public ErrorDialog(XElement errorDialog)
{
self = errorDialog;
}
public int errorDialogId
{
get { return (int)(self.Element("error_dialog_id")); }
}
public string errorDialogMessage
{
get { return (string)(self.Element("error_dialog_message")); }
}
public string errorDialogTitle
{
get { return (string)(self.Element("error_dialog_title")); }
}
public bool errorDialogIsSet
{
get { return (bool)(self.Element("error_dialog_is_set")); }
}
public List<ErrorDialogChoice> errorDialogChoice
{
get { return (List<ErrorDialogChoice>)(errorDialogChoice); }
}
public int errorDialogSelectedOption
{
get { return (int)(self.Element("error_dialog_selected_option")); }
}
}
class ErrorDialogChoice
{
XElement self;
public ErrorDialogChoice() { }
public ErrorDialogChoice(XElement errorDialogChoice)
{
self = errorDialogChoice;
}
public int errorDialogChoiceOptionId
{
get { return (int)(self.Element("error_dialog_choice_option_id")); }
}
public string errorDialogChoiceOptionTitle
{
get { return (string)(self.Element("error_dialog_choice_option_title")); }
}
}
And here's how I'm parsing it:
XElement response = XElement.Parse(data);
ErrorDialog[] dialogs = response
.Element("response_error_dialogs")
.Element("error_dialog_list")
.Elements("error_dialog_choice")
.Select(e => new ErrorDialog(e))
.ToArray();
ErrorDialogChoice[] edChoices = response
.Element("response_error_dialogs")
.Element("error_dialog_list")
.Element("error_dialog_choice")
.Element("error_dialog_choice_option_list")
.Elements("error_dialog_choice_option")
.Select(e => new ErrorDialogChoice(e))
.ToArray();
So with this example, the first error_dialog_choice object will have a List containing 3 error_dialog_choice_option objects, the second has the two error_dialog_choice_option objects, and any more that may come back. Any help is appreciated. Thanks.
You can use XML serialization to achieve this much easier:
var reader = new StringReader(xmlString);
var ser = new XmlSerializer(typeof(Response));
var result = (Response) ser.Deserialize(reader);
Using these class definitions.
[XmlType("response")]
public class Response
{
[XmlElement("response_error_dialogs")]
public ErrorDialog ErrorDialog;
}
[XmlType("response_error_dialogs")]
public class ErrorDialog
{
[XmlArray("error_dialog_list")]
public List<ChoiceErrorDialog> ChoiceList;
}
[XmlType("error_dialog_choice")]
public class ChoiceErrorDialog
{
[XmlElement("error_dialog_id")]
public int Id;
[XmlElement("error_dialog_message")]
public string Message;
[XmlElement("error_dialog_title")]
public string Title;
[XmlElement("error_dialog_is_set")]
public bool IsSet;
[XmlArray("error_dialog_choice_option_list")]
public List<Option> OptionList;
}
[XmlType("error_dialog_choice_option")]
public class Option
{
[XmlElement("error_dialog_choice_option_id")]
public int Id;
[XmlElement("error_dialog_choice_option_title")]
public string Title;
}
I am guessing there can be more types of error dialogs, and <error_dialog_choice> is just one of the possible types. In this case you could use subclassing, and list the subclasses with XmlArrayItem attributes.
You could also generate the class definitions with xsd.exe or svcutil.exe, from an .xsd or .wsdl file. xsd.exe can even infer the schema from a sample .xml file.
xsd.exe /?
svcutil.exe /?
Use the XmlSerializer built into the framework. Use attributes to map out the xml equivalent of your classes and their properties.
Example:
[XmlElement("Txn")]
public List<Transaction> Items { get; set; }
You can use the XSD.exe to generate an XSD and then generate C# code for your XSD. Use Visual Studio Command Prompt with a sample response.xml file. Eg:
c:>xsd response.xml
c:>xsd response.xsd /c /edb

Different behavior between 'Service Reference' and 'Web Reference'

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">
<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; }
}
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”.
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.

Categories