Passing serialized object through web service vs. Passing the object - web-services

I have a webservice in C#.NET with the following namespace:
[WebService (Namespace = "http://enterpriseName/wsName")]
The web service contains a WebMethod GetServiceObject and a class MyObject.
This web method returns a string whose content is a serialized instance of MyObject.
[WebMethod (MessageName = "GetServiceObjectXML" Description = "Get ServiceObject from Server to Client")]
public string GetServiceObjectXML ()
This method returns the following XML:
<? Xml version = "1.0" encoding = "utf-16"?>
<ServiceObject Xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Services>
<service>
<id>3</id>
<date>02/08/2010</date>
</service>
</Services>
</ServiceObject>
The problem that I encounter is that when I call this method from the client side and try to deserialize this xml to class MyObject and I get a NULL object.
After that I created a new WebMethod with the following signature:
[WebMethod (MessageName = "GetServiceObject" Description = "Get ServiceObject from Server to Client")]
public MyObject GetServiceObject ()
When I call this method from the client side I get the object filled correctly and I can also serialize the object without problems, but the result of serialization is the following xml:
<? Xml version = "1.0" encoding = "utf-16"?>
<ServiceObject Xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Services Xmlns="http://enterpriseName/wsName">
<service>
<id>3</id>
<date>02/08/2010</date>
</service>
</Services>
</ServiceObject>
which is different from the xml generated by the WebMethod GetServiceObjectXML.
How can I get around this, since I intend to use both methods on the same webservice and in the same customer?

The obvious answer would be, fix GetServiceObjectXML() to return the same XML as GetServiceObject(). The difference seems to be that the object as serialized by the framework has a different XML namespace specified. Whatever method you're using to serialize the object into XML in GetServiceObjectXML() isn't doing that.

Related

Implementing Soap Webservice: Handling Complex object argument

My company has subscribed to a service offered by a travel reservation system whereby they call us back when any changes occur to a travel itinerary. My task is to stand up a SOAP endpoint to accept this callback. I am doing this with standard jax-ws stuff.
Here is the essentials of their soap message:
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:eb="http://www.ebxml.org/namespaces/messageHeader" xmlns:swse="http://wse.sabre.com/eventing"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wse="http://schemas.xmlsoap.org/ws/2004/08/eventing">
<soap-env:Header>
<eb:MessageHeader eb:version="1.0"
soap-env:mustUnderstand="1">
<wse:MySubscription>7TZA</wse:MySubscription>
<swse:EventTopic>WSE.QUEUE.CCC.PNRCHNG</swse:EventTopic>
</eb:MessageHeader>
<wsa:Action>http://wse.sabre.com/EventSource/notification</wsa:Action>
<wsa:MessageID>721d8dc0-1307-4b27-a48b-a9ba7f7818c7</wsa:MessageID>
<wse:Identifer>7f9aad13-a8cd-4057-8c91-89ccfad64598</wse:Identifer>
<wsa:To>http://localhost:18888/</wsa:To>
</soap-env:Header>
<soap-env:Body>
<swse:CCC.PNRCHNG>
<swse:OWNPCC>N0V3</swse:OWNPCC>
<swse:HOMEPCC>W0H3</swse:HOMEPCC>
<swse:Locator>IGLYIZ</swse:Locator>
<swse:EventTimeStamp format="yyyy-MM-dd hh:mm:ss.fffffffff">2007-10-30 11:41:32.000986</swse:EventTimeStamp>
<swse:ChangeIndicators>
<swse:Indicator name="Ticketing">
<swse:hasChanged>Y</swse:hasChanged>
</swse:Indicator>
...
</swse:CCC.PNRCHNG>
</soap-env:Body>
I have a functioning SOAPHandler with a getHeaders() implementation wich is satisfying the mustUnderstand=1 requirement.
I have a #WebMethod that is successfully accepting a few of the top level parts of the payload. This is actually good enough for now, but I would like to understand how to write a #Webmethod that would accept the whole payload as a complex object.
I have a jibx-generated CCC.PNRCHNG class. But how would I write the #WebMethod to accept it? Below is the method that accepts the top level bits as separate #WebParams (Locator is all I really need right now)
#WebMethod(operationName="CCC.PNRCHNG", action="http://wse.sabre.com/EventSource/notification")
public Object onPnrEvent(
#WebParam(name="OWNPCC", targetNamespace=NS) String ownPcc,
#WebParam(name="HOMEPCC", targetNamespace=NS) String homePcc,
#WebParam(name="Locator", targetNamespace=NS) String locator
) {
try {
s_logger.info(locator);
}
catch(Exception e) {
s_logger.error(e);
}
return null;
}
It would be nice to get the full model so any advice there would be very much appreciated.
Best way would be to generate PortType based on WSDL with wsimport. If you don't have a WSDL, I wouldn't bother with writing a wrapped JAX-WS service.
On your class, add this annotation
#SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
Then write methods that accept the root element. Something like this:
#WebMethod(operationName="CCC.PNRCHNG", action="http://wse.sabre.com/EventSource/notification")
public Object onPnrEvent( #WebParam(name="CCC.PNRCHNG", targetNamespace=NS) PNRCHNG request) {
}

How to construct soap message with xsd element name rather element type

<xsd:element name="echodemo" type="EchodemoType">
<xsd:annotation>
<xsd:documentation>
Root element
</xsd:documentation>
</xsd:annotation>
this is my XSD.
but when i had generate the java object from xsd by chooing generate java in RSA ., it generating EchodemoType.java ..
so am creating instance LIKE below before passing the request to my service
EchodemoType request = new EchodemoType();
request.setEchoRequest("This is Echo String !!!");
request .setVersion(new BigDecimal("1.0"));
while invoke my webservice am seeing the the soap message like below.,
<EchodemoType version="1.0">
<ns2:echoRequest>This is Echo String !!!</ns2:echoRequest>
</EchodemoType>
basically i want the soap message start tag with element name "echodemo" rather with type "EchodemoType".also i want it with the name space
<echodemo version="1.0" xmlns="http://test.com/api/test/services/echodemo">
<ns2:echoRequest>This is Echo String !!!</ns2:echoRequest>here
</echodemo>
please tell me the way to generate the class to have that soap message or where i need to correct this?
Make use of Object Factory for mashelling the object like below you no need to have #XmlRootElement in DemoType.java .,
DemoType demoServiceRequest = new DemoType();
demoServiceRequest.setName("fgfg");
ObjectFactory obDemo = new ObjectFactory();
Request requestObject = new Request();
requestObject.setAny(obDemo.createDemo(demoServiceRequest));
And add DemoType class at Request.java like #XmlSeeAlso({DemoType.class})

Create sub-tags in Matlab Soap request

I am developing a SOAP client in Matlab for connection a Web Service. What I am doing is the following script:
createClassFromWsdl('http://192.168.107.239/WSDL/v4.0/iLON100.wsdl')
obj = iLON100
methods(obj)
With the next result:
Methods for class iLON100:
Clear Get List Set display
Delete InvokeCmd Read Write iLON100
Then, I am editing for example the method List in order to request the list of Items for the service. The dot m file is:
% Build up the argument lists.
values = { '','//Item[#xsi:type="Dp_Cfg"]'};
names = { 'iLonItem','xSelect'};
types = {};
% Create the message, make the call, and convert the response into a variable.
soapMessage = createSoapMessage('http://wsdl.echelon.com/web_services_ns/ilon100/v4.0/message/',
'List', values, names, types, 'document');
I have also a SOAP tester from the vendor of the device. Then, if I compare both XML requests, they differ as you can see in the next example (firstly the original request and secondly the Matlab one):
<SOAP-ENV:Body>
<List xmlns="http://wsdl.echelon.com/web_services_ns/ilon100/v4.0/message/">
<iLonItem>
<xSelect>
//Item[#xsi:type="Dp_Cfg"]
</xSelect>
</iLonItem>
</List>
</SOAP-ENV:Body>
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<List xmlns="http://wsdl.echelon.com/web_services_ns/ilon100/v4.0/message/">
<iLonItem/>
<xSelect>Item</xSelect>
</List>
</soap:Body>
As you can observe, the tags are not included as sub-tags. I would like to know how to do it and generate the same structure of XML for sending the SOAP request correctly.
Thank you so much,
At the end, I have solved it by creating a structure as follows:
myStruct = struct('iLonItem',struct('xSelect','//Item[#xsi:type="Dp_Cfg"]'))
This structure is inserted into "values" and the method's name "iLONItem".

how replace XmlGregorianCalendar by Date?

I have to expose an ejb service layer via jax-ws .
I have generated the web service using jax-ws and wsimport but I'm stopped by a strange things ; Date are being mapped to XmlGregorianCalendar .
Is it possible to use classic java Date instead ?
Can you show me the right way to proceed ?
Thanks .
Edit:
this the binding file i used :
thanks , I modified slightly your xml and attached it with netbeans to the client's webservice and it worked . This the binding I used :
<jaxws:bindings node="wsdl:definitions/wsdl:types/xsd:schema"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" wsdlLocation="../wsdl/localhost_8080/web_test/Testor.wsdl" >
<jaxb:globalBindings>
<jaxb:javaType name="java.util.Date"
xmlType="xsd:dateTime"
parseMethod="lol.XsdDateTimeConverter.unmarshal"
printMethod="lol.XsdDateTimeConverter.marshalDateTime"
/><jaxb:javaType
name="java.util.Date"
xmlType="xsd:date"
parseMethod="lol.XsdDateTimeConverter.unmarshal"
printMethod="lol.XsdDateTimeConverter.marshalDate"
/>
</jaxb:globalBindings>
</jaxws:bindings>
Not tested, but should work. First create such class:
import javax.xml.bind.DatatypeConverter;
public class XsdDateTimeConverter {
public static Date unmarshal(String dateTime) {
return DatatypeConverter.parseDate(dateTime).getTime();
}
public static String marshalDate(Date date) {
final GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(date);
return DatatypeConverter.printDate(calendar);
}
public static String marshalDateTime(Date dateTime) {
final GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(dateTime);
return DatatypeConverter.printDateTime(calendar);
}
}
Then add this to custom xjb file:
<javaType
name="java.util.Date"
xmlType="xs:dateTime"
parseMethod="XsdDateTimeConverter.unmarshal"
printMethod="XsdDateTimeConverter.marshalDateTime"
/>
<javaType
name="java.util.Date"
xmlType="xs:date"
parseMethod="XsdDateTimeConverter.unmarshal"
printMethod="XsdDateTimeConverter.marshalDate"
/>
</globalBindings>
Not tested, but should work. Based on my answer here: JAX-WS and Joda-Time?
Thanks Tomasz. The above solution works.
But wsimport also adds its set of Adapters like Adapter1.java and Adapter2.java with its package org.w3._2001.xmlschema, which really doesnot match my own package structure.
I found a way to change this package name using another jaxb binding. Actually, I searched for this a lot and could not find this easily, so I am adding it here for anyone looking for the same.
Add the following binding in the wsimport using '-b binding.xml'. Note that wsimport can work with multiple binding files.
binding.xml content below:
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:version="2.0">
<annotation><appinfo>
<jaxb:schemaBindings>
<jaxb:package name="com.abc.xyz.utils"/>
</jaxb:schemaBindings>
</appinfo></annotation>
</schema>

How to Declare Complex Nested C# Type for Web Service

I would like to create a service that accepts a complex nested type. In a sample asmx file I created:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
// [System.Web.Script.Services.ScriptService]
public class ServiceNest : System.Web.Services.WebService
{
public class Block
{
[XmlElement(IsNullable = false)]
public int number;
}
public class Cell
{
[XmlElement(IsNullable = false)]
public Block block;
}
public class Head
{
[XmlElement(IsNullable = false)]
public Cell cell;
}
public class Nest
{
public Head head;
}
[WebMethod]
public void TakeNest(Nest nest)
{
}
}
When I view the asmx file in IE the test page shows the example SOAP post request as:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<TakeNest xmlns="http://schemas.intellicorp.com/livecompare/">
<nest>
<head>
<cell>
<block xsi:nil="true" />
</cell>
</head>
</nest>
</TakeNest>
</soap:Body>
</soap:Envelope>
It hasn't expanded the <block> into its number member.
Looking at the WSDL, the types all look good. So is this just a limitation of the post demo page creator?
Thanks.
But those elements ARE null. You need to construct them before they show up otherwise they are just null.
As Kevin pointed out the example POST XML indicates that those elements are nil. I should have simply tried to consume the web service. Once I did that I could see that the importer (either .NET, Java or Ruby) correctly created all the types. So really there is no question here after all.
The .NET code did not give up after a certain number of levels.
If you look at the code generated by "Add Web Reference", you'll find that there's a bool numberSpecified field. Only if the client sets that to true will the number be serialized.
If you look at the XML Schema, you'll see that the number element might be absent. If it were of a reference type, then that could be represented in the client by a null value. Since it's an int, this additional flag is necessary to indicate whether or not to serialize this optional value.