I have a java webserver that I need to communicate with using a wsdl contract. I didn't built the server, and I don't have access to its source code. I built a c# application and I added the service reference to the wsdl contract using visual studio "add service reference". I paste the part of the wsdl I am interested in:
<wsdl:operation name="SOAPRequestItemHead" parameterOrder="SessionID searchitems">
<wsdl:input message="impl:SOAPRequestItemHeadRequest" name="SOAPRequestItemHeadRequest"/>
<wsdl:output message="impl:SOAPRequestItemHeadResponse" name="SOAPRequestItemHeadResponse"/>
</wsdl:operation>
<wsdl:operation name="SOAPRequestItemHead">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="SOAPRequestItemHeadRequest">
<wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://wrapper.soap.aplusb.com" use="encoded"/>
</wsdl:input>
<wsdl:output name="SOAPRequestItemHeadResponse">
<wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://192.168.200.26:8888/tcdnc/services/fsw" use="encoded"/>
</wsdl:output>
</wsdl:operation>
<wsdl:message name="SOAPRequestItemHeadResponse">
<wsdl:part name="SOAPRequestItemHeadReturn" type="tns2:SOAPItemRevisionHeadResult"/>
</wsdl:message>
<complexType name="SOAPItemRevisionHeadResult">
<sequence>
<element maxOccurs="1" minOccurs="0" name="comment" nillable="true" type="xsd:string"/>
<element name="searchComplete" type="xsd:boolean"/>
<element maxOccurs="unbounded" minOccurs="0" name="search" type="tns2:StringMap"/>
<element maxOccurs="unbounded" minOccurs="0" name="resultList" type="tns2:SOAPItemRevisionHead"/>
</sequence>
</complexType>
Note that resultList and search are arrays. If I call this method, here is the raw response, taken with a SOAP tool:
<SOAPRequestItemHeadReturn xmlns:ns2="fsw" xsi:type="ns2:SOAPItemRevisionHeadResult">
<comment xsi:type="xsd:string" xsi:nil="true"/>
<searchComplete xsi:type="xsd:boolean">true</searchComplete>
<resultList xsi:type="ns2:SOAPItemRevisionHead">
<search xsi:type="ns2:StringMap">
<stringKey xsi:type="xsd:string">ItemRevision.ItemID</stringKey>
<stringValue xsi:type="xsd:string">cam_english_template</stringValue>
</search>
<search xsi:type="ns2:StringMap">
<stringKey xsi:type="xsd:string">ItemRevision.Revision</stringKey>
<stringValue xsi:type="xsd:string">A</stringValue>
</search>
<dummy xsi:type="xsd:string" xsi:nil="true"/>
</resultList>
<resultList xsi:type="ns2:SOAPItemRevisionHead">
...
As you see, resultList and search are actually arrays. But when I call the method from my c# client, I get this error:
Error in deserializing body of reply message for operation 'SOAPRequestItemHead'.
Inner Exception: There is an error in XML document (1, 815).
Inner Exception: Cannot assign object of type StringMap to an object of type StringMap[]
And if I go to the Reference.cs that is automatically generated, and I manually change the type of the two properties that are supposed to be arrays from StringMap[] to StringMap the error is not thrown, but of course I can only get the first item of the array in my program. I hope I was clear, even if it's a long question.
Update: I know this is a problem with using Axis 1.4, that uses rcp/encoded instead of document/literal, so the question can be reformulated in these terms: "can .NET correctly handle rcp/encoded?"
Check the data contracts generated by VS. They should contain specific type for the 'resultList' as well, decorated with CollectionDataContract attribute. I would also check whether the namespaces and names are set precisely on DataContract attributes.
EDIT: about RPC style web services you can find some workaround on these links:
http://social.msdn.microsoft.com/Forums/vstudio/en-US/51babae5-26e5-4405-b03c-4301710854c0/why-does-add-service-reference-fail-to-build-a-proper-reference-for-dfa?forum=wcf
http://social.msdn.microsoft.com/Forums/vstudio/en-US/07edda1a-d0d5-4920-b2fb-a25c803269d6/trouble-with-consuming-a-java-rpc-web-service-using-net-client?forum=wcf
As far I can see, something is wrong in SOAPItemRevisionHeadResult type definition in th WSDL.
<complexType name="SOAPItemRevisionHeadResult">
<sequence>
<element maxOccurs="1" minOccurs="0" name="comment" nillable="true" type="xsd:string"/>
<element name="searchComplete" type="xsd:boolean"/>
<element maxOccurs="unbounded" minOccurs="0" name="search" type="tns2:StringMap"/>
<element maxOccurs="unbounded" minOccurs="0" name="resultList" type="tns2:SOAPItemRevisionHead"/>
</sequence>
</complexType>
A type with this definition maps to:
Public class SOAPItemRevisionHeadResult{
public string comment;
public boolean searchComplete;
public Stringmap[] search;
public SOAPItemRevisionHead[] resultList;
}
Public class StringMap{
//can't see definition of this type in your part of WSDL posted but doesn't matter.
//guesed definition by looking at the response
public string StringKey;
public string StrigValue;
//end of guesed definition
}
Public class SOAPItemRevisionHead{
//can't see definition of this type in your part of WSDL posted but doesn't matter.
//guesed definition by looking at the response
public StringMap[] search;
//end of guesed definition
}
Seems bad nesting classes in WSDL but in the Raw Response you posted I can see the correct nesting:
Public class SOAPItemRevisionHeadResult{
public string comment;
public boolean searchComplete;
public resultList as SOAPItemRevisionHead[];
}
Public class SOAPItemRevisionHead{
public StringMap[] search;
}
Public class StringMap{
public string StringKey;
public string StrigValue;
}
Possibly you want to consider an alternative to that encoding if possible, see:
http://security-world.blogspot.dk/2005/07/nt-aspnet-rcpencoded-web-service-dos.html
I believe the answer you're searching for is in this post:
http://social.msdn.microsoft.com/Forums/vstudio/en-US/51babae5-26e5-4405-b03c-4301710854c0/why-does-add-service-reference-fail-to-build-a-proper-reference-for-dfa?forum=wcf
Corrected link above, don't know why the wrong one got in there
Related
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?
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.
Is there a way to actually enforce generating FooSpecified for non-complex types like strings or integers?
The Web Service I am working with defines all record fields as nillable and minOccurs = 0
<xsd:complexType name="Constituent">
<xsd:complexContent mixed="false">
<xsd:extension base="tns:Record">
<xsd:sequence>
<xsd:element minOccurs="0" maxOccurs="1" name="ConsId" nillable="true" type="xsd:nonNegativeInteger" />
<xsd:element minOccurs="0" maxOccurs="1" name="SiteId" nillable="true" type="xsd:nonNegativeInteger" />
<xsd:element minOccurs="0" maxOccurs="1" name="PredupStatus" nillable="true" type="xsd:string" />
It also specifies Update method with Record as argument:
<xsd:element name="Update">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="0" maxOccurs="1" name="PartitionId" nillable="true" type="xsd:nonNegativeInteger" />
<xsd:element minOccurs="0" maxOccurs="1" name="Force" nillable="true" type="xsd:boolean" />
<xsd:element minOccurs="1" maxOccurs="unbounded" name="Record" type="ens:Record" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
Constituent Record has nearly 200 elements, which can be null.
At the same time, Update method on the server side is programmed to ignore all null values if there are more than 10 of them in the update request.
Reference.cs generated from the file does not contain *Specified properties for strings or integers
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.7.3062.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:object.soap.convio.com")]
public partial class Constituent : Record {
private string consIdField;
private string siteIdField;
private string predupStatusField;
private System.Nullable<AdministratorStatus> adminStatusField;
private bool adminStatusFieldSpecified;
hich causes XmlSerializer to generate lines for each field:
<q1:ConsId xsi:nil="true"/>
<q1:SiteId xsi:nil="true"/>
<q1:PredupStatus xsi:nil="true"/>
<q1:AdminStatus xsi:nil="true"/>
<q1:ConsName><q1:Title xsi:nil="true"/>
<q1:FirstName>234234</q1:FirstName>
<q1:MiddleName xsi:nil="true"/>
<q1:LastName>412341234</q1:LastName>
Which works fine until I try to blank a field out. At that point the field I am trying to blank out is being send as null and is being ignored by the server because there are more than 10 null fields in the request. To be able to remove unwanted null lines from serialization I need all fields to have *Specified property and send in the request only the field I want to be null. I can add them manually, but it's a lot of work that I need to remember to save somewhere else to avoid being removed when refreshing service reference...
Alternatively, is there a way to enforce generating ShouldSerialize property in Reference.cs?
I have received a wsdl from a java webservice team and when I try to generate c# proxy class using svcutil, it gives me an error on faults and doesn't generate those. I get the below error.
Warning: Fault named ProvApiException in operation put cannot be
imported. Unsupported WSDL, the fault message part must reference
an element. This fault message does not reference an element. If you
have edit access to the WSDL document, you can fix the problem by
referencing a schema element using the 'element' attribute.
I looked up the error and changed 'type' to 'element'. I also used /useSerializerForFaults option when generating the class, still no luck. It keeps giving me other errors. What should I edit in the wsdl to generate the faults? Also, any other option I should use in svcutil?
<complexType name="ProvApiException">
<sequence>
<element name="errorCode" nillable="true" type="xsd:string"/>
<element name="message" nillable="true" type="xsd:string"/>
<element name="rootCause" nillable="true" type="xsd:string"/>
</sequence>
I am trying to consume the following WSDL in VS2010 and Im running into errors which seem to be specific to the WSDL.
I am adding it as a Web Service Reference, and initially no proxy classes or anything are created - the wizard completes successfully and I get a .wsdl and a Reference.map file under ~/Web References/ in the project, however the service is unavailable in code.
If I do an "Update Web Reference" on it, I get the following error:
Custom tool error: Unable to import WebService/Schema. The element attribute is not allowed on encoded message parts. The erroneous part is named 'textReturnObject' in message 'singleTextResponse'. (File: Reference.map line 1 column 1)
If I try and rename "element" to "type" i get a whole bunch of other issues:
The custom tool 'MSDiscoCodeGenerator' failed. Cannot find definition for http://schemas.xmlsoap.org/wsdl/:exampleServiceNameBinding. Service Description with namespace http://schemas.xmlsoap.org/wsdl/ is missing.
Parameter name: name
Can anyone shed any light on it? I've put the WSDL through some online tools and they consume it fine - does VS2010 have an issue with certain types of WSDL?
<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.example.com/exampleServiceName" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/" name="exampleServiceName" targetNamespace="http://www.example.com/exampleServiceName" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<xsd:complexType name="exampleType">
<sequence>
<element minOccurs="1" maxOccurs="1" name="title" type="string" />
<element minOccurs="1" maxOccurs="1" name="url" type="string" />
<element minOccurs="1" maxOccurs="1" name="description" type="string" />
</sequence>
</xsd:complexType>
<wsdl:types />
<wsdl:message name="singleTextRequest">
<wsdl:part name="intIdentity" type="xsd:integer" />
</wsdl:message>
<wsdl:message name="singleTextResponse">
<wsdl:part name="textReturnObject" element="wsdl:exampleType" />
</wsdl:message>
<wsdl:portType name="exampleServiceNamePortType">
<wsdl:operation name="singleTextAdvert">
<wsdl:input message="tns:singleTextRequest" />
<wsdl:output message="tns:singleTextResponse" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="exampleServiceNameBinding" type="tns:exampleServiceNamePortType">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc" />
<wsdl:operation name="singleText">
<soap:operation soapAction="urn:xmethods-delayed-quotes#singleText" />
<wsdl:input>
<soap:body use="encoded" namespace="urn:xmethods-delayed-quotes" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
</wsdl:input>
<wsdl:output>
<soap:body use="encoded" namespace="urn:xmethods-delayed-quotes" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="exampleServiceNameService">
<wsdl:port name="exampleServiceNamePort" binding="wsdl:exampleServiceNameBinding">
<soap:address location="http://www.example.com/exampleServiceName/Server.php" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
I have a question on SO where I had trouble adding a service reference. I ended up using svcutil as recommended and it solved the problem. My situation was slightly different, but it's worth a try.
.net web service: Can't add service reference, only web reference
Yes, VS2010 can't create a web service reference from some WSDLs. Have to write custom wrapper for those. OR edit your WSDL in a way so VS can consume it. For example it may be ok for you to remove web service method references for the methods that you are not planning to use if those references create trouble for you.
How can I add a XML prefix to fields in WCF Message Serialization?
I'm connecting up to a Java Spring web service from .NET, and an object that I pass in with parameters is being serialized as you would expect:
<MyClass>
<field1>Field 1 Value</field1>
<field2>Field 2 Value</field2>
</MyClass>
However, the web service requires that the class and fields are prefixed with a namespace, let's say namespace blah, so what I want is:
<blah:MyClass>
<blah:field1>Field 1 Value</blah:field1>
<blah:field2>Field 2 Value</blah:field2>
</blah:MyClass>
How can I make this happen in WCF? Is there a way to adjust the XML serialization attributes on my class?
Edit: WSDL for this particular entity is as follows (edited to remove business-specific field names, but everything else is the same):
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:sch0="http://www.domain.com/app/schemas/entityone" xmlns:sch1="http://www.domain.com/app/schemas/types" xmlns:sch2="http://www.domain.com/app/schemas/query" xmlns:sch3="http://www.domain.com/app/schemas/entitytwo" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://www.domain.com/app/schemas/entityone" targetNamespace="http://www.domain.com/app/schemas/entityone">
<wsdl:types>
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:types="http://www.domain.com/app/schemas/types" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://www.domain.com/app/schemas/entityone" xmlns:tns="http://www.domain.com/app/schemas/entityone">
<import namespace="http://www.domain.com/app/schemas/types" />
<element name="TheClassName">
<complexType>
<sequence>
<element name="field1" type="string" />
<element name="field2" type="string" />
<element name="field3" type="string" />
<element name="field4" type="string" />
<element name="field5" type="string" />
<element name="field6" type="string" />
<element name="field7" type="string" />
<element name="field8" type="string" />
</sequence>
</complexType>
</element>
<wsdl:binding name="NameOfBindingHere" type="tns:ReturnTypeHere">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="OperationNameHere">
<soap:operation soapAction="" />
<wsdl:output name="ResponseTypeHere">
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
I think you are confusing namespaces and prefixes. In your example Blah is the prefix and is a pointer (alias) to the namespace. In the document, you will see an attribute xmlns:blah="http://tempuri/your/namespace", the prefix is blah and the namespace is http://tempuri/your/namespace.
What the prefix is used does not matter to whomever consumes the document, as long as it points to the same exact namespace.
so
<blah:MyClass xmlns:blah="http://tempuri/your/namespace"></blah:MyClass>
is the exact same thing as
<blah1:MyClass xmlns:blah1="http://tempuri/your/namespace"></blah1:MyClass>
XML Schema does not require that what prefix should be used.
Aliostad's DataContract example is exactly how to define the namespace that the Data Contract Serializer will use. There is no way to define what prefix the DataContract Serializer will use, because whatever the prefix is doesn't matter. That is as long as the service consuming this XML is adheres to XML standards (and isn't something like a RegEx expression, and believe me I've seen plenty of cases where the consumer of the XML was a custom written text parser instead of using an XML parser and didn't grasp the concept of XML Namespaces and Infosets).
Try defining MyClass as:
DataContract(namespace="blah")
Class MyClass
{
[DataMember]
Field1 ...
[DataMember]
Field2 ...
}
UPDATE
This will not create the prefix but the prefix would not be needed if XML has the correct namespace and Java should work.