Reputation: 2789
I need to create a SOAP service which needs to be consumed by a third-party application to accomplish a task (callback). The below is the C# interface they've specified in their documentation and I think they've already developed the consumer so it is my responsibility to create the server according to the specification.
public interface ICallback
{
void Delivery(Info info, Item[] items)
string TestCallback(string data)
}
Additionally the below are how Info
and Item
classes look like:
class Info
{
public int Id {get; set;}
public string Name {get; set;}
}
class Item
{
public int Id {get; set;}
public string Name {get; set;}
public string Value {get; set;}
}
To create the service in spyne I wrote the below code
from spyne import (
Application,
rpc,
ServiceBase,
Iterable,
Integer,
Unicode,
ComplexModel,
)
from spyne.protocol.soap import Soap11
from spyne.server.wsgi import WsgiApplication
import logging
logging.getLogger().setLevel(logging.INFO)
class Info(ComplexModel):
Id = Integer
Name = Unicode
class Item(ComplexModel):
Id = Integer
Name = Unicode
Value = Unicode
class Callback(ServiceBase):
@rpc(Info, Iterable(Item))
def Delivery(ctx, info, item):
logging.info(f">>>> Info - {info}")
for i in range(item):
logging.info(f">>>>>>>> item - {i}")
@rpc(Unicode, _returns=Unicode)
def TestCallback(ctx, data):
logging.info(f">>>> Test - {data}")
return data
application = Application(
[Callback],
"spyne.examples.hello.soap",
in_protocol=Soap11(validator="lxml"),
out_protocol=Soap11(),
)
wsgi_application = WsgiApplication(application)
And noticed spyne wraps the arguments to a single class. The callback service from the third-party API is not aware of this wrapping so it is failing. I presume this is how spyne works and felt like the maintainers of spyne should have perhaps acknowledged this limitation.
However a server created using Core WCF gives me the wsdl which does not wrap the argument rather just keep them as they are. So the callback service which is provided by the third party API just works as expected.
I went to compare the generated XML and found spyne generates the following xml for the particular operation:
<wsdl:operation name="Delivery" parameterOrder="Delivery">
<wsdl:input name="Delivery" message="tns:Delivery"/>
<wsdl:output name="DeliveryResponse" message="tns:DeliveryResponse"/>
</wsdl:operation>
In the <wsdl:types>
the below is how the Delivery
is specified (this is where the wrapping happens)
<xs:complexType name="Delivery">
<xs:sequence>
<xs:element name="info" type="s0:Info" minOccurs="0" nillable="true"/>
<xs:element name="items" type="s0:Item" minOccurs="0" nillable="true"/>
</xs:sequence>
</xs:complexType>
...
<xs:element name="Delivery" type="tns:Delivery"/>
However the Core WCF generates a separate wsdl which looks like below:
<wsdl:operation name="Delivery">
<wsdl:input wsaw:Action="http://tempuri.org/IService/Delivery" message="tns:IService_Delivery_InputMessage"/>
<wsdl:output wsaw:Action="http://tempuri.org/IService/DeliveryResponse" message="tns:IService_Delivery_OutputMessage"/>
</wsdl:operation>
...
<wsdl:message name="IService_Delivery_InputMessage">
<wsdl:part name="parameters" element="tns:Delivery"/>
</wsdl:message>
...
<xs:element name="Delivery">
<xs:complexType>
<xs:sequence>
<xs:element xmlns:q2="http://schemas.datacontract.org/2004/07/API.Receiver" minOccurs="0" name="info" nillable="true" type="q2:Info"/>
<xs:element xmlns:q3="http://schemas.datacontract.org/2004/07/API.Receiver" minOccurs="0" name="item" nillable="true" type="q3:item"/>
</xs:sequence>
</xs:complexType>
</xs:element>
Here the key difference is spyne keeps name for the complex type (<xs:complexType>
), which is resulting in the wrapper while Core WCF avoids the name. Additionally according to this documentation, the name is only required if the containing element is the schema element; otherwise, prohibited.
The above is my findings and I just want to validate if my understanding is correct. Can anyone please let me know if this is correct?
Additionally, I also would like to know either spyne or Core WCF follows the W3C standard?
Upvotes: 0
Views: 159
Reputation: 8001
I thought going over your question point-by-point would be easiest, so here we go:
And noticed spyne wraps the arguments to a single class.
This is how soap works. The parent tag's namespace (ie. the immediate child of the soap:Envelope
element)'s namespace and name taken together forms the name of the remote procedure you are calling.
The following schema fragment
<xs:complexType name="Delivery">
<xs:sequence>
<xs:element name="info" type="s0:Info" minOccurs="0" nillable="true"/>
<xs:element name="items" type="s0:Item" minOccurs="0" nillable="true"/>
</xs:sequence>
</xs:complexType>
...
<xs:element name="Delivery" type="tns:Delivery"/>
and the following schema fragment
<xs:element name="Delivery">
<xs:complexType>
<xs:sequence>
<xs:element xmlns:q2="http://schemas.datacontract.org/2004/07/API.Receiver" minOccurs="0" name="info" nillable="true" type="q2:Info"/>
<xs:element xmlns:q3="http://schemas.datacontract.org/2004/07/API.Receiver" minOccurs="0" name="item" nillable="true" type="q3:item"/>
</xs:sequence>
</xs:complexType>
</xs:element>
are equivalent.
Here the key difference is Spyne keeps name for the complex type (<xs:complexType>), which is resulting in the wrapper while Core WCF avoids the name.
This is not correct. Spyne serializes schema elements separately in a reusable way (so that it's serialized only once) whereas .net seems to embed the types. Both are valid approaches.
Additionally according to this documentation, the name is only required if the containing element is the schema element; otherwise, prohibited.
The parent of the xs:complexType
tag in the spyne example is indeed the <schema>
element, so there are no issues here.
Additionally, I also would like to know either spyne or Core WCF follows the W3C standard?
Can't speak about what .NET does, but Spyne implements a subset of the W3C's XML Schema 1.0 standard (among other ones). I've made every effort for the implemented parts to be conformant. I'm happy to fix any deviations and welcome patches that add the missing bits.
Upvotes: 1