wcf icon indicating copy to clipboard operation
wcf copied to clipboard

dotnet-svcutil cannot handle recursively nested XSD structures

Open schneoka opened this issue 1 year ago • 9 comments

Here is an excerpt from our WSDL definition. The structure oel_CmisExtensionTypeList is recursively nested:

<xsd:complexType name="oel_CmisExtensionTypeList">
 <xsd:sequence>
  <xsd:element name="item" minOccurs="0" maxOccurs="unbounded" nillable="true" type="s0:oel_CmisExtensionType"/>
 </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="oel_CmisExtensionType">
 <xsd:sequence>
   <xsd:element name="key" minOccurs="0" maxOccurs="1" type="xsd:string"> </xsd:element>
   <xsd:element name="value" minOccurs="0" maxOccurs="1" type="xsd:string"> </xsd:element>
   <xsd:element name="any" minOccurs="0" maxOccurs="1" type="s0:oel_CmisExtensionTypeList"> </xsd:element>
 </xsd:sequence>
</xsd:complexType>

<xsd:element name="ObjectService__performTaskActionRequest">
 <xsd:complexType>
  <xsd:sequence>
   <xsd:element name="username" minOccurs="1" maxOccurs="1" type="xsd:string"> </xsd:element>
   <xsd:element name="extension" minOccurs="0" maxOccurs="1" type="s0:oel_CmisExtensionTypeList"> </xsd:element>
  </xsd:sequence>
 </xsd:complexType>
</xsd:element>

To generate the WCF class this command was used: dotnet-svcutil http://localhost:17089/wsdl --namespace "*, COI.SOAPConnector" --internal --sync --reference "c:\Program Files\dotnet\sdk\8.0.100\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Collections.dll" --noStdLib --outputFile BflowWSDL.cs --targetFramework "net8.0"

The generated class (I also tried dotnet-svcutil 2.1.0, it does not work either) looks like this:

  [System.Diagnostics.DebuggerStepThroughAttribute()]
   [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.2.0-preview1.23462.5")]
   [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
   [System.ServiceModel.MessageContractAttribute(WrapperName="ObjectService__performTaskActionRequest", WrapperNamespace="http://www.coi.de/bflowsoap", IsWrapped=true)]
   internal partial class ObjectService__performTaskActionRequest
   {
       [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.coi.de/bflowsoap", Order=0)]
       public string username;
       
       [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.coi.de/bflowsoap", Order=3)]
       [System.Xml.Serialization.XmlArrayItemAttribute("item")]
       public COI.SOAPConnector.COI.SOAPConnector.oel_CmisExtensionType[] extension;

The definition of extension contains two errors: Firstly, the namespace COI.SOAPConnector appears twice: COI.SOAPConnector.COI.SOAPConnector.oel_CmisExtensionType[] and secondly, the XSD definition contains a reference to oel_CmisExtensionTypeList, not to oel_CmisExtensionType

The svcutil used with .NET6 has generated the correct code here. Even if the duplicate namespace is corrected manually, the transfer of values in extension.any no longer works.

schneoka avatar Jan 15 '24 10:01 schneoka

Update:

  1. the double namespace issue doesn't repro on my side
  2. svcutil.exe behaves the same as dotnet-svcuitl.exe
  3. As reproduced base on the given information, oel_CmisExtensionTypeList type contains only one property, so the tool extracted that single member type (oel_CmisExtensionType[]) to the container type oel_CmisExtensionType, it doesn't seem to affect service op functionality if invoke by passing the required operation parameter. If type oel_CmisExtensionTypeList contains more than 1 property, type oel_CmisExtensionTypeList will be generated separately and be referenced as defined by the container type.

imcarolwang avatar Mar 01 '24 09:03 imcarolwang

@schneoka , since I was unable to reproduce the first "double namespace" problem, the example serivce/wsdl I created to reproduce the issue may be missing some key information compared to yours. Therefore, the conclusion mentioned in my previous comments for the second issue may not apply to you. Can you provide a fully constructed simplified wsdl file that reproduces the issue?

imcarolwang avatar Mar 08 '24 02:03 imcarolwang

@imcarolwang, i used this command to create the file: dotnet-svcutil http://localhost:17089/wsdl --namespace "*, COI.BusinessFlow.API.CmisClient.Binding.SOAPConnector" --internal --sync --reference "c:\Program Files\dotnet\sdk\8.0.100\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Collections.dll" --noStdLib --outputDir .\CmisClient\Binding\SOAPConnector --outputFile BflowWSDL.cs --targetFramework "net8.0"

  1. For example, in the created file, line 5414:

public COI.BusinessFlow.API.CmisClient.Binding.SOAPConnector.COI.BusinessFlow.API.CmisClient.Binding.SOAPConnector.oel_CmisExtensionType[] extension;

  1. Example with svcutil:
internal partial class ObjectService__performTaskActionRequest
{
 ...
 [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.coi.de/bflowsoap", Order=3)]
  public COI.BusinessFlow.API.CmisClient.Binding.SOAPConnector.oel_CmisExtensionTypeList extension;
   ..     
  public ObjectService__performTaskActionRequest(string username, string actionId, COI.BusinessFlow.API.CmisClient.Binding.SOAPConnector.oel_CmisPropertiesType properties, COI.BusinessFlow.API.CmisClient.Binding.SOAPConnector.oel_CmisExtensionTypeList extension)

Example with dotnet-svcutil:

internal partial class ObjectService__performTaskActionRequest
{
 ...
 [System.Xml.Serialization.XmlArrayItemAttribute("item")]
 public COI.BusinessFlow.API.CmisClient.Binding.SOAPConnector.COI.BusinessFlow.API.CmisClient.Binding.SOAPConnector.oel_CmisExtensionType[] extension;
 ... 
 public ObjectService__performTaskActionRequest(string username, string actionId, COI.BusinessFlow.API.CmisClient.Binding.SOAPConnector.oel_CmisPropertiesType properties, COI.BusinessFlow.API.CmisClient.Binding.SOAPConnector.COI.BusinessFlow.API.CmisClient.Binding.SOAPConnector.oel_CmisExtensionType[] extension)

It was a lot of work to change the access to member extension from list to array type, but it still doesn't work. The extension parameter provides no data.

The WSDL WSDL.xml This is the created file BflowWSDL.cs

schneoka avatar Mar 08 '24 15:03 schneoka

@schneoka thank you for the information! It's very helpful, and I'm able to reproduce both of the issues described.

I found out that it was "xsd:integer" that was causing the problem, if update the given WSDL file by replacing the two occurrences of "xsd:integer" with "xsd:int", dotnet-svcutil will be able to generate the code as expected.

I'm wondering how you defined your service that its WSDL would contain "xsd:integer". Can you share the corresponding service contract definition? Thanks!

imcarolwang avatar Mar 15 '24 09:03 imcarolwang

@imcarolwang Isn't that the definition in https://www.w3.org/2001/XMLSchema?

<xs:simpleType name="integer" id="integer">
<xs:annotation>
<xs:documentation source="http://www.w3.org/TR/xmlschema-2/#integer"/>
</xs:annotation>
<xs:restriction base="xs:decimal">
<xs:fractionDigits value="0" fixed="true" id="integer.fractionDigits"/>
<xs:pattern value="[\-+]?[0-9]+"/>
</xs:restriction>
</xs:simpleType>

schneoka avatar Mar 15 '24 12:03 schneoka

Hi @schneoka, I have a proposed fix to address this issue and I tried to run the private "fixed" build against the WSDL.xml you provided, here is the cs file that was generated: BflowWSDL2.txt, would you mind try it out in your project and see if it works?

imcarolwang avatar Mar 19 '24 02:03 imcarolwang

@imcarolwang The new cs file works in our project, thank you very much.

schneoka avatar Mar 20 '24 05:03 schneoka