How to check WCF data element skipped in XML? - wcf

In my WCF I defined an object "Product" as below:
<xs:complexType name="Product">
<xs:sequence>
<xs:element name="Name" type="xs:string"/>
<xs:element name="Postcode" type="xs:string" nillable="true" minOccurs="0"/>
<xs:element name="ProductID" type="xs:string" />
</xs:sequence>
</xs:complexType>
Please note the element "Postcode" is nillable="true" minOccurs="0", this means when client application call the web service, they can either provide empty value for this element as below:
<Product>
<Name>Product 1</Name>
<Postcode></Postcode>
<ProductID>10</ProductID>
</Product>
Or they can simple skip "Postcode" element so the incoming message becomes this (Postcode isn't there)
<Product>
<Name>Product 1</Name>
<ProductID>10</ProductID>
</Product>
My question is, in my host program how do I check if the element "Postcode" exists in the incoming XML message? I am asking because if it doesn't there and I call the method to get Postcode value, then the program will throw an error:
string postcode = product.Postcode - this call will throw an error?
Thank you all very much for any ideas/suggestions.
Charles

You are not correct in your assertion that using nillable in your definition permits the two cases you have listed.
In fact, the nillable xsd attribute permits the construction:
<Postcode xsi:nil='true'/>
which is semantically different from Postcode being either empty, or just not present at all.
In answer to your question,
how do I check if the element "Postcode" exists in the incoming XML
message
I don't quite understand why you want to define Postcode with minOccurs=0. When wcf receives this type across the wire it will attempt to deserialise to a predefined C# type. In C#, types either have properties or they don't have.
eg.
public class Product
{
public string Postcode { get; set; }
}
is not the same things as
public class Product
{
}
So by allowing callers to construct two different versions of your Product type you are actually forced to define two separate C# types to deserialise to, which means you'll need to expose your service operation twice, once for callers who want to use Product with postcode, and one for those who want to use Product without.
I would suggest that you redefine your Product type to include the Postcode element - after all because it's a string your callers can just leave it null if they do not wish to use it.

Related

Remove Type form Apache apache.cxf.tools.wsdlto.WSDLToJava in generated source

I am trying to consume a WSDL, generate source form WSDL and XSDs in gradle using org.apache.cxf.tools.wsdlto.WSDLToJava. It generates classname as it is in XSDs and WSDL, but I want change all the generated class names in similar way. I know I can add binding file to it, but I would need to have entry for every element in the WSDL.
Please help me with a generic for all the properties.
e.g XSD below :
<xs:complexType name="SomeType">
<xs:sequence>
<xs:element name="SomeType2" type="CommonNS:Some2Type"/>
<xs:element name="SomeType3" type="CommonNS:Some3Type" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
The classes generated are :
com.something.SomeType
com.something.Some2Type
com.something.Some3Type
But I want to generate it as :
com.something.Some
com.something.Some2
com.something.Some3

XSLT for BizTalk mapping and changing node name

I need to map 2 fields from a large schema to a small schema (below), to produce a message to be sent to make a web service call.
<xs:element name="ds">
<xs:complexType>
<xs:sequence>
<xs:element name="ID" type="xs:string"></xs:element>
<xs:element name="d1" type="xs:string"></xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
The same web method is used to update many different items, so contains 2 parameters: ID and another general update field which will take the text value of the update.
The ID parameter is always called ID, but depending on the type of item I have to update, the second parameter will change it's name.
So, in the BizTalk map (which I'm guessing should be XSLT):
The first field mapped across is an ID field, going from TargetID in source to ID in destination. This is a direct mapping.
The second field will always be mapped to a field called 'd1'.
Based on an xsl:if, the node name of d1 will change.
eg:
if changeType in large schema = 'forename', d1 will become d_forename
if changeType in large schema = 'surname', d1 will become d_surname and so on.
There are going to be around 20 possible changeTypes, so I guess my question is, if I use an xsl:choose to evaluate the changeType (which will give me my ID and update value) how can I at the same time return the new name for the <d1> node? I know it will be a called template but unsure where to start with this.
What you are looking for is presumable the possibilities around element naming.
What happens most of the time is the following:
<d_someOtherNode>
<xsl:value-of select="/root/someOtherNode/text()" />
</d_someOtherNode>
However, what you can also do is:
<xs:element name="{concat('d_', name(/root/someOtherNode))}">
<xsl:value-of select="/root/someOtherNode/text()" />
</xs:element>
The latter allows you to name the element as you please, in this case, concatenating the d_ and name of the element you need (someOtherNode ).
Put this in the "if" structure or choose/when structure as you please, depending on your solution.

WCF contract mismatch case that is working

I have a WCF service hosted on 2 servers. There was a function called GetData(param1).
I changed this function to accept 2 parameters i.e. GetData(param1,param2).
I updated the service on server1 and I updated the client code.
A weird thing is happening. the updated client code still works with the outdated service although the functions don't match. The function is being called and the results are returned. The added parameter is an enumeration value type if that helps. But why have such a non-deterministic behavior? and how does it work?
This thing is that when you design your method in a procedural way all you input parameters are optional by default and are populated with default values if you don't specify them explicitly. Assume you have a method with the following signature:
[OperationContract]
void TestMethod(string param1, int param2);
You will get the following WSDL for it:
<xs:element name="TestMethod">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="param1" nillable="true" type="xs:string" />
<xs:element minOccurs="0" name="param2" type="xs:int" />
</xs:sequence>
</xs:complexType>
</xs:element>
As you can see minOccurs attribute has 0 value which means the element is optional. So this is not surprising that your method works even after you added a new parameter.
If you want to avoid this behavior try to design your contracts in a message way by using MessageContract or at least wrapping all you parameters in a container class. And specify explicitly which parameter is required and if it allows default value via DataMember attribute.
Hope it helps!
If your service has installed more than once place. Recheck your endpoint address to ensure its pointing right hosted server.

Why is JAXB generating the wrong XML for my WCF service?

I have a WCF service that expects an object which I'll call StuffContainer. Our client is trying to generate an XML-serialized StuffContainer using JAXB, but it's coming out wrong. They're ending up with type names where they should have property names, so we're not able to deserialize it.
I know nothing about JAXB, but I gather it creates some auto-generated classes based on our XSD, which can be used to build the XML-serialized object.
Here's the relevant snippet of our auto-generated XSD:
<xs:complexType name="StuffContainer">
<xs:sequence>
<xs:element minOccurs="0" name="myStuff" nillable="true" type="tns:ArrayOfStuff"/>
</xs:sequence>
</xs:complexType>
...
<xs:complexType name="ArrayOfStuff">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="Stuff" nillable="true" type="tns:Stuff"/>
</xs:sequence>
</xs:complexType>
Our client's code looks something like this:
ObjectFactory objectFactory = new ObjectFactory();
ArrayOfStuff arrayOfStuff = objectFactory.createArrayOfStuff();
JAXBElement<ArrayOfStuff> arrayOfStuffJAXBElement = objectFactory.createArrayOfStuff(arrayOfStuff);
StuffContainer stuffContainer = objectFactory.createStuffContainer();
stuffContainer.setStuff(arrayOfStuffJAXBElement);
Here's the XML they're getting:
<StuffContainer xmlns="..."><ArrayOfStuff>...</ArrayOfStuff></StuffContainer>
But I need it to be:
<StuffContainer xmlns="..."><myStuff>...</myStuff></StuffContainer>
I think this is because the JAXBElement<ArrayOfStuff> that they're getting from the objectFactory has its QName set to "ArrayOfStuff", and this ends up getting used instead of the property name myStuff. But like I said I know nothing about JAXB so I'm not sure what they should be doing differently.
Is there something either that I can change in the XSD, or that I can ask our client to change in their code, so that it generates the correct XML?
There may be multiple methods on the generated ObjectFactory class. The ones corresponding to nested elements have an entire path built into the method name.

wcf : string element nillable="false"

I have a client that is mandating that my required string elements have nillable="false", currently all strings in the wsdl come out will nillable="true", IE:
<xs:element name="username" nillable="true" type="xs:string" />
How can i change the nillable="false" ?!? I will take any suggestions on how to do this? Am I the first person that has run into this?
How is this element defined in your data contract?
If it's not already done, try adding a IsRequired=true clause to the data member attribute:
[DataContract]
class YourDataStructure
{
......
[DataMember(IsRequired=True)]
string username;
.....
}
Other than that, I'm not aware of any way to influence the XSD being rendered from your WCF data contract, short of writing your own WsdlExporter extension (which is totally possible - just seems a bit overkill here).