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>
Related
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
My understanding of XML isn't exactly stunning, but my understanding of content in annotation/appinfo is that you're allowed any well-formed XML, and this is lax validated. My understanding of lax validation is that elements and attributes will be validated if the relevant schema information can be obtained.
My situation is that I have an XML schema with some content in this section that requires validating. I have the relevant schemas to validate the content against.
I've taken a totally simple XML schema and added an appinfo element to it, as shown below. The content of the appinfo is another element declaration, purely for simplicity of not referencing another schema. The schema I'm trying to validate obviously references something different.
<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.demo.org"
xmlns="http://www.demo.org"
elementFormDefault="qualified">
<xsd:annotation>
<xsd:appinfo>
<xsd:element name="Demo">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="A" type="xsd:iteger"/>
<xsd:element name="B" type="xsd:integer"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:appinfo>
</xsd:annotation>
<xsd:element name="Demo">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="A" type="xsd:integer"/>
<xsd:element name="B" type="xsd:integer"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
Note in the appinfo section, I've deliberately mis-spelled "integer" on element A. If I do this in the main body of the schema, then XmlSchemaSet.Compile() will tell me this schema isn't valid.
However, if I use the schema as it's written above, it tells me there is no problem. In the more complex file I started with, I supplied the external schema to XmlSchemaSet via XmlSchemaSet.Add()
I've also tried loading the XML schema from http://www.w3.org/2001/XMLSchema.xsd and loading the schema to be validated into an XmlDocument and running XmlDocument.Validate() but no joy.
I feel like I'm totally missing something totally fundamental after spending hours on this. Any pointers appreciated!
This is not my understanding of lax: if you have a declaration
<any
namespace=". . . "
processContents="lax">
</any>
the content of the corresponding element in the XML being validated will be validated against the schemas corresponding to the namespace(s) specified by namespace (if any) - not against any schema it might be using. The declaration for appInfo is
<xs:element name="appinfo" id="appinfo">
<xs:complexType mixed="true">
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:any processContents="lax"/>
</xs:sequence>
<xs:attribute name="source" type="xs:anyURI"/>
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:complexType>
</xs:element>
without any namespace specification, that corresponds to namespace="##any", that means that there is no validation against any schema.
Today I have the folowwing xsd declaration that is generated to Array
<xs:element name="SubNodes" type="Node" minOccurs="0" maxOccurs="unbounded"/>
How can I do something that will be generated to List<> ?
(Using c#)
Update:
I've tried
<xs:simpleType name="SubNodes">
<xs:list itemType="Node"/>
</xs:simpleType>
but got the error:
The 'http://www.w3.org/2001/XMLSchema:simpleType' element is not
supported in this context
What tool are you using to generate the wsdl? I will assume it is visual studio.
In that case when you generate the service reference, click "Advanced" and you should see this screen where you can select the collection type:
I am generating a datacontract with svcutil from a webservice.
svcutil /language:cs /noConfig /targetclientversion:Version35
/out:Generated\ProductService.cs http://example.com/ProductService.svc?wsdl
The fields generated looks like this:
private System.Nullable<System.DateTime> createdField;
private bool createdFieldSpecified;
How can the fields be both nullable and have a specified field?
it depends on the source Wsdl. I bet there is something this (not sure of the syntax):
<xsd:element name="created" type="xsd:datetime" minOccurs="0" xsd:nil="true" />
svcutil.exe use nillable to produce a Nullable<> field, and minOccurs to produce a field + specified combination.
I also bet the WSDL is not a .Net generated WSDL !
The class generation is driven by XSD schema of the web service.
In order to generate nullable fields. The field should be marked as nillable.
<xs:element minOccurs="0" maxOccurs="1" name="created" type="xs:dateTime" nillable="true" />
The XML will look like this.
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<created xsi:nil="true" />
</root>
I believe that this field in your schema looks like this:
<xs:element minOccurs="0" maxOccurs="1" name="created" />
and it would omit the element completely if createdFieldSpecified = false:
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
</root>
The bottom line: web service schema should be updated in order to generate nullable fields with svcutil.
I have created a C# .net 2.0 webservice. I need to capture the raw XML sent from the client and validate it against an XSD and return any errors to the client. The webservice will allow the client to upload a list of widgets to our system.
The following is some background info:
I created an XSD to model a "Widget", which is a complex object. It looks something like this:
<xs:element name="WidgetList">
<xs:complexType>
<xs:sequence>
<xs:element name="Widget" maxOccurs="unbounded" type="WidgetType" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="WidgetType">
<xs:sequence maxOccurs="1" minOccurs="1">
<xs:element name="Seller" type="AccountType" maxOccurs="1" minOccurs="1" />
<xs:element name="Buyer" type="AccountType" maxOccurs="1" minOccurs="1" />
</xs:sequence>
<xs:attribute name="Market" type="MarketType" use="required" />
</xs:complexType>
<!-- etc... -->
Then, I used XSD.exe to generate classes from the xsd.
The Classes that are created are WidgetList, Widget, Seller, Buyer, etc.
Next, I created a webservice method to take the Upload. It looks like so:
[WebMethod]
[SoapHeader("SecurityAuthenticationHeader", Direction = SoapHeaderDirection.In)]
public string UploadWidgets(WidgetList wl)
{
//Need to validate the XML against the XSD here.
//Code to import...
}
Two questions:
Is there a way that I can validate the raw XML sent from the client against my original XSD?
Is there anything wrong with the way I have created this service?
UPDATE:
The reason I need to do this is that even though the XSD says fields are required or minOccurs=1, it seems that those properties are not required in the WSDL (Not really sure why).
This is what part of the WSDL looks like (removed unnecessary parts for brevity):
<s:schema elementFormDefault="qualified" targetNamespace="http://www.clearpar.com/XMLSchema">
<s:element name="lt">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="unbounded" name="LoanTrade" type="s1:LoanTradeType" />
</s:sequence>
</s:complexType>
</s:element>
<s:complexType name="LoanTradeType">
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="Seller" type="s1:AccountType" />
<s:element minOccurs="0" maxOccurs="1" name="Buyer" type="s1:AccountType" />
</s:sequence>
<s:attribute name="Market" type="s1:MarketType" use="required" />
</s:complexType>
<s:complexType name="AccountType">
<s:attribute name="Name" type="s:string" />
<s:attribute name="ClientSystemID" type="s:string" />
</s:complexType>
I don't think that there's a simple way to do this.
There is an MSDN article on implementing a SoapExtension to perform schema validation. This is the route I took, with a few enhancements.
It's unfortunate that there is no automatic mechanism to validate against the WSDL, especially since the service inherently knows the schema already. I would be interested to know if this situation has changed in WCF: I'm porting my services now and would love it if they've solved this problem more elegantly.
Since you need more strict control over your WSDL, I recommend writing it manually, and generate both your service contract interface/data/messages and client proxies from a single WSDL contract. There is a great project on CodePlex, WCSF.blue, that can help you do contract-first service development.
For question 1: the only way that I know to validate the incoming message is to create SOAP Extension that validates the incoming message against the expected schema. The reason is that the .NET plumbing deserializes the incoming XML into an object before entering your WebMethod. If there is an issue with the incoming XML then your Web Method will never be entered and a SOAP Fault will be returned to the client. Another issue is that perhaps the deserializer does not deserialize "properly". Read the XML Schema Validation article for more information.
In terms of question 2: your approach is correct for contract first development using (asmx) web services. My question back to you is why not use WCF to expose a web service instead of the older ASMX technology. WCF supports schema validation as well.