How to move a class property without breaking a web service contract? - c#

I recently made some changes to a WCF WebService that broke my web service contract. I'm hoping there's a way that I can generate the same/similar WSDL that is backwards compatible (currently, UpdateTypes is always = 0/None no matter what I set it to in my client code)
My code below only shows the sections that are pertinent to the issue.
This was the way my code looked like originally:
public enum UpdateTypes
{
None = 0,
Insert = 1,
Update = 2,
Delete = 3
}
[DataContract()]
public class BaseEntity
{
[DataMember()]
public UpdateTypes UpdateType {get; set;}
}
public class User : BaseEntity
{
//...other properties and methods
}
Which generated a WSDL that looked like this:
<xs:complexType name="BaseEntity">
<xs:sequence>
<xs:element minOccurs="0" name="UpdateType" type="tns:UpdateTypes" />
</xs:sequence>
</xs:complexType>
<xs:element name="BaseEntity" nillable="true" type="tns:BaseEntity" />
<xs:simpleType name="UpdateTypes">
<xs:restriction base="xs:string">
<xs:enumeration value="None" />
<xs:enumeration value="Insert" />
<xs:enumeration value="Update" />
<xs:enumeration value="Delete" />
</xs:restriction>
</xs:simpleType>
<xs:element name="UpdateTypes" nillable="true" type="tns:UpdateTypes" />
And this is what I changed my class code to which broke my Web Service contract:
public class User : IUpdateable
{
[DataMember()]
public UpdateTypes UpdateType { get; set; }
//...other properties and methods
}
because it changed the WSDL to look like this (notice that the BaseEntity section is now missing):
<xs:simpleType name="UpdateTypes">
<xs:restriction base="xs:string">
<xs:enumeration value="None" />
<xs:enumeration value="Insert" />
<xs:enumeration value="Update" />
<xs:enumeration value="Delete" />
</xs:restriction>
</xs:simpleType>
<xs:element name="UpdateTypes" nillable="true" type="tns:UpdateTypes" />
This causes the UpdateType to always be 0 when it gets to the newly updated WCF Service Endpoint application.

You can direct WCF to use a custom WSDL which matches your original contract, although it is not trivial. Here's a microsoft example adding documentation to the WSDL:
http://msdn.microsoft.com/en-us/library/aa717040(v=vs.110).aspx

Related

XML Schema Union getting "string" is not valid for the element error

I am an experienced programmer but just recently took on a job maintaining an app that uses xml schema. They want to add some validation on an item that accepts Longitude. They want to continue to accept a blank and also 0, 0.0000000, or if another value is entered they want to make sure that at the least it is in the United States. (i.e. between -125 and -67)
The current xml schema simply allows any value.
<xs:element name="Location">
<xs:complexType>
<xs:sequence>
<xs:element name="LocLongitude"/>
</xs:sequence>
</xs:complexType>
</xs:element>
There are multiple venders sending this info in. Here is an example of what they may send:
<Location>
<LocLongitude xsi:type="xsd:string"></LocLongitude>
</Location>
Now looking at what the users want I found that I can use a union to encapsulate multiple checks. This is what I am using now.
<xs:element name="Location">
<xs:complexType>
<xs:sequence>
<xs:element name="LocLongitude" nillable="true">
<xs:simpleType>
<xs:union>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value=""/>
<xs:enumeration value="0"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType>
<xs:restriction base="xs:double">
<xs:minInclusive value="0.00000000"/>
<xs:maxInclusive value="0.00000000"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType>
<xs:restriction base="xs:double">
<xs:minInclusive value="-125"/>
<xs:maxInclusive value="-67"/>
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
It validates correctly if I use:
<Location>
<LocLongitude />
</Location>
Now if I use what the current vendors are using (see below):
<Location>
<LocLongitude xsi:type="xsd:string"></LocLongitude>
</Location>
We get an error:
THE XSI:TYPE ATTRIBUTE VALUE '' IS NOT VALID FOR THE ELEMENT 'LOCLONGITUDE', EITHER BECAUSE IT IS NOT A TYPE VALIDLY DERIVED FROM THE TYPE IN THE SCHEMA, OR BECAUSE IT HAS XSI:TYPE DERIVATION BLOCKED.
My question is, can I get this to work while still allowing the vendors to include xsi:type="xsd:string"?
No, the type chosen for xs:type must be validly derived from the type provided by the associated element. You cannot on the one hand define a type that restricts the value space and on the other hand supports a broader xs:type declaration.
See also: How to restrict the value of an XML element using xsi:type in XSD?

WCF Schema common elements always null

I am using xsd to generate the object available in the OperationContract. The address, city, state and zip elements of the XSD are common
<xs:element name="Address" nillable="true">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="50"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
and used throughout the XML.
<xs:element ref="Address" />
When I compile the schema the classes generate correctly using the common elements.
When I run the service the OperationContext contains the expected request from the client:
<NameLast>Last</NameLast>
<NameFirst>First</NameFirst>
<Address xmlns="http://tempuri.org/">123 2nd St</Address>
<City xmlns="http://tempuri.org/">Somewhere</City>
However the common elements have the xmlns attribute (shown above) and in the received object all common elements contain null values.
My reputation is not high enough to show screenshot, but all data NOT in common elements are passed correct. Such as NameLast = "Last", Address = Null.
I am new to using Schemas and would appreciate any direction. Thanks.
I believe what you want is this, placed before your closing </xs:schema> tag:
<xs:simpleType name="AddressType">
<xs:restriction base="xs:string">
<xs:maxLength value="50"/>
</xs:restriction>
</xs:simpleType>
and used throughout the schema:
<xs:element name="Address" type="AddressType" />

Creating an XSD to authenticate a C# flag enumeration

I have a flag enumeration of commands that can be executed
[Flags]
public enum Operations
{
InstallNothing = 0,
InstallStateDatabase = 1,
InstallStateServer = 2,
InstallStoreDatabase = 4,
InstallStoreServer = 8,
InstallMaintenanceProgram = 16,
InstallOther=32
}
[XmlElement("Commands")]
public Operations Commands { get; set; }
I want to be able to read an XML file and parse it against an xsd. I have this section of my xsd attempting to handle the validation but i don't think this is right.
<xs:element name="commands" maxOccurs="1" minOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element name="command" minOccurs="1" maxOccurs="unbounded" >
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="InstallNothing" />
<xs:enumeration value="InstallStateDatabase" />
<xs:enumeration value="InstallStateServer" />
<xs:enumeration value="InstallStoreDatabase" />
<xs:enumeration value="InstallStoreServer" />
<xs:enumeration value="InstallMaintenanceProgram" />
<xs:enumeration value="InstallOther" />
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
The XMLs are going to be created by hand so i don't want to store the int value as the creators will not know what the int values are supposed to be.
I want my C# code to remain unchanged if possible and redesign my XSD to reflect what is supposed to be in my C# code. Right now, some generated text XML that VS2013 generates has multiple different command elements. I know that is how my XSD is written, but this isn't want a I want. I want one element that has can have any of the strings in the enumeration. How do i set up this XSD and what would an example XML look like of this implementation sending multiple different commands.
I found my answer(s) at
xsd select multiple values from enumeration or equivalent type. I wasn't searching the right thing earlier...
i added a list to my commands element. Here is my xsd after the change:
<xs:element name="commands" maxOccurs="1" minOccurs="1">
<xs:simpleType>
<xs:list>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="InstallNothing" />
<xs:enumeration value="InstallStateDatabase" />
<xs:enumeration value="InstallStateServer" />
<xs:enumeration value="InstallStoreDatabase" />
<xs:enumeration value="InstallStoreServer" />
<xs:enumeration value="InstallMaintenanceProgram" />
<xs:enumeration value="InstallOther" />
</xs:restriction>
</xs:simpleType>
</xs:list>
</xs:simpleType>
</xs:element>
and an example xml using it is:
<commands>InstallNothing InstallStateDatabase InstallStateServer </commands>

XML element has invalid child element 'X', expected 'X'

I have created some XSD schemas and receive the below error when trying to read from it in C#:
The element PartnerPSTNTransfer in namespace 'http://localhost/Orders-PartnerPSTNTransfer-v1-0' has invalid child element 'StartDate' in namespace 'http://localhost/Orders-Connection-v1-0'.
List of possible elements expected: 'StartDate' in namespace 'http://localhost/Orders-PartnerPSTNTransfer-v1-0'.
However the expected element is StartDate and it is present in the xml file so I am unsure why this error would be shown. I'll attatch the .xsd for the schemas i created:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="PartnerPSTN"
targetNamespace="http://localhost/Orders-PartnerPSTN-v1.0"
elementFormDefault="qualified"
xmlns="http://localhost/Orders-PartnerPSTN-v1.0"
xmlns:mstns="http://localhost/Orders-PartnerPSTN-v1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:a="http://localhost/Orders-Address-v1-0"
xmlns:c="http://localhost/Orders-Common-v1-0" >
<xs:simpleType name="Contract">
<xs:restriction base="xs:token">
<xs:enumeration value="Monthly_12"></xs:enumeration>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="PackageOption">
<xs:restriction base="xs:string">
<xs:enumeration value="Data Only" />
<xs:enumeration value="Free Evening and Weekend" />
<xs:enumeration value="1000 Anytime" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="FeatureOption">
<xs:list>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="Feature0"/>
<xs:enumeration value="Feature0.A"/>
<xs:enumeration value="Feature0.B"/>
<xs:enumeration value="Feature0.C"/>
<xs:enumeration value="Feature1"/>
<xs:enumeration value="Feature2"/>
<xs:enumeration value="Feature2.A"/>
<xs:enumeration value="Feature3"/>
<xs:enumeration value="Feature3.A"/>
<xs:enumeration value="Feature3.B"/>
<xs:enumeration value="Feature3.C"/>
</xs:restriction>
</xs:simpleType>
</xs:list>
</xs:simpleType>
<xs:complexType name="PartnerPSTNConfiguration">
<xs:sequence>
<xs:element name="Package" type="PackageOption" />
<xs:element name="Feature" type="FeatureOption" />
</xs:sequence>
</xs:complexType>
</xs:schema>
Schema 2:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="PartnerPSTNTransfer"
targetNamespace="http://localhost/Orders-PartnerPSTNTransfer-v1-0"
elementFormDefault="qualified"
xmlns="http://localhost/Orders-PartnerPSTNTransfer-v1-0"
xmlns:mstns="http://localhost/Orders-PartnerPSTNTransfer-v1-0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:a="http://localhost/Orders-Address-v1-0"
xmlns:padsl="http://localhost/Orders-PartnerPSTN-v1.0"
xmlns:c="http://localhost/Orders-Common-v1-0"
xmlns:conn="http://localhost/Orders-Connection-v1-0">
<xs:import namespace="http://localhost/Orders-Common-v1-0" schemaLocation="../../Common.xsd" />
<xs:import namespace="http://localhost/Orders-PartnerPSTN-v1.0" schemaLocation="PartnerPSTN.xsd" />
<xs:complexType name="PartnerPSTNTransfer">
<xs:sequence>
<xs:element name="TelephoneNumber" type="c:Landline" />
<xs:element name="StartDate" type="xs:date" />
<xs:element name="Postcode" type="c:RequiredString" />
<xs:element name="Configuration" type="padsl:PartnerPSTNConfiguration" />
</xs:sequence>
</xs:complexType>
<xs:element name="PartnerPSTNTransfer" type="PartnerPSTNTransfer"></xs:element>
</xs:schema>
EDIT
Here is my XML I am trying to validate:
<p:PartnerPSTNTransfer xmlns:padsl="http://localhost/Orders-PartnerPSTN-v1.0"
xmlns:p="http://localhost/Orders-PartnerPSTNTransfer-v1-0"
xmlns:a="http://localhost/Orders-Address-v1-0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://localhost/Orders-Connection-v1-0">
<p:TelephoneNumber>01111111111</p:TelephoneNumber>
<c:StartDate>2014-10-10T00:00:00</c:StartDate>
<c:Postcode>XX1 1XX</c:Postcode>
<p:Configuration>
<padsl:Contract>MA</padsl:Contract>
<padsl:PackageOption>Weekend</padsl:PackageOption>
<padsl:Featureoption>Feature0 Feature2.A</padsl:Featureoption>
</p:Configuration>
</p:PartnerPSTNTransfer>
EDIT 2
XML so far. I beleive I've removed the original problem although it now says:
The element 'Configuration' in namespace 'http://localhost/Orders-PartnerPSTNTransfer-v1-0' has invalid child element 'Contract' in namespace 'http://localhost/Orders-PartnerPSTN-v1.0'.
and the XML being:
<p:PartnerPSTNTransfer xmlns:padsl="http://localhost/Orders-PartnerPSTN-v1.0"
xmlns:p="http://localhost/Orders-PartnerPSTNTransfer-v1-0"
xmlns:a="http://localhost/Orders-Address-v1-0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://localhost/Orders-Connection-v1-0">
<p:TelephoneNumber>01111111111</p:TelephoneNumber>
<p:StartDate>2014-10-10</p:StartDate>
<p:Postcode>EX20 1LP</p:Postcode>
<p:Configuration>
<padsl:Package>Free Evening and Weekend</padsl:Package>
<padsl:Feature>Feature0 Feature2.A</padsl:Feature>
<padsl:Contract>Monthly_12</padsl:Contract>
</p:Configuration>
</p:PartnerPSTNTransfer>
Your xml instance says it's looking for an element called StartDate which is defined somewhere in a schema under the namespace http://localhost/Orders-Connection-v1-0:
<c:StartDate>2014-10-10T00:00:00</c:StartDate>
where:
xmlns:c="http://localhost/Orders-Connection-v1-0"
Your schema, however, defines this element as belonging to a type called PartnerPSTNTransfer under the namespace http://localhost/Orders-PartnerPSTNTransfer-v1-0
So you need to modify your instance so that StartDate references the correct namespace it's containing type was defined under. You have already referenced the namespace at root level under the namespace prefix of "p" so you should be able to do:
<p:StartDate>2014-10-10T00:00:00</p:StartDate>
(And the same for PostCode element).
EDIT
In response to the second part of your question, the xml instance resolves to an element called Contract defined in type PartnerPSTNConfiguration in namespace http://localhost/Orders-PartnerPSTN-v1.0
However the definition for PartnerPSTNConfiguration in the schema does not contain a definition for Contract, only for Package and Feature:
<xs:complexType name="PartnerPSTNConfiguration">
<xs:sequence>
<xs:element name="Package" type="PackageOption" />
<xs:element name="Feature" type="FeatureOption" />
</xs:sequence>
</xs:complexType>
So to be valid you have to model the Contract element in the PartnerPSTNConfiguration type definition, eg:
<xs:complexType name="PartnerPSTNConfiguration">
<xs:sequence>
...
<xs:element name="Contract" type="SomeType" />
</xs:sequence>
</xs:complexType>
Or, change your instance to not expect it to be there.

C#.NET Generating web service reference using WSDL (from XML schema) problem

I am using VS2010 and using the "add service reference" feature, to generate client classes from my WSDL. I am having a problem with one of my elements, which is defined in the WSDL as follows:
<xs:simpleType name="NumberType">
<xs:restriction base="xs:string">
<xs:enumeration value="ONE" />
<xs:enumeration value="TWO" />
<xs:enumeration value="THREE" />
</xs:restriction>
</xs:simpleType>
This type is used in one of my elements like this:
<xs:element name="NumberTypes">
<xs:simpleType>
<xs:list itemType="tns:NumberType" />
</xs:simpleType>
</xs:element>
The problem is that VS is converting this particular element to a string type, when it should be an enumeration. so it converts it to a string NumberTypes which has a get method returning numberTypesField also of type string.
I think the problem is related to the fact that my schema NumberTypes element uses the xs:list, with 'itemType' attribute. if I change this to xs:element with type="tns:NumberType" attribute instead then the enumeration is generated as it should be.
So how can I make the enumeration work with xs:list? Why is it not converting correctly in the first place?
Thanks for any help.
I haven't had much luck getting xs:list to serialize properly. Instead, I just allow for multiple instances of the same node, and .NET knows how to put it into a "list" or "array" properly.
<xs:element minOccurs="0" maxOccurs="unbounded" name="NumberTypes">
...
</xs:element>

Categories

Resources