Custom attributes don't show up in WSDL

Hello everyone,

I’m building a proof-of-concept soap webservice on which or descision will be based if we buy the Remoting SDK or not. The last hurdle appears to be marking fields in the wsdl as optional.

So far I have been able to figure out that you can do this by using the attributes “minOccurs” and “maxOccurs” in your WSDL. For Example:

<xs:complexType name="CollectionContainerType">
 <xs:sequence>
  <xs:element minOccurs="0" maxOccurs="1" name="IdContainer" type="xs:string"/>
  <xs:element minOccurs="1" maxOccurs="1" name="IdSupplierContainer" type="xs:unsignedInt"/>
  <xs:element minOccurs="0" maxOccurs="1" name="IdSubContainer" type="xs:string"/>
 </xs:sequence>
</xs:complexType>

I am using codefirst, since this was the recomended way when building new services. As I have found you can decorate your class like this:

  CodeValuePairType = class(TROComplexType)
  private
    FCode: Cardinal;
    FValue: string;
  published
    [ROCustom('minOccurs','1')]
    [ROCustom('maxOccurs','1')]
    property Code: Cardinal read FCode write FCode;
    [ROCustom('minOccurs','0')]
    [ROCustom('maxOccurs','1')]
    property Value: string read FValue write FValue;
  end;

Note that the condecompletion in Delphi gives ROCustomAttribute, but the endresult is in both cases that in the wsdl not a single custom attribute is to be seen:

     <xs:complexType name="CodeValuePairType">
        <xs:sequence>
           <xs:element name="Code" type="xs:int"/>
           <xs:element name="Value" type="xs:string"/>
        </xs:sequence>
     </xs:complexType>

What am I doing wrong?

Hi,

If you declare struct as

  [ROCustom('IsSimpleTypeExtension','1')]
  CodeValuePairType_Value_Optional = class(TROComplexType)
  private
    FValue: string;
  published
    property Value: string read FValue write FValue;
  end;

  CodeValuePairType = class(TROComplexType)
  private
    FCode: Cardinal;
    FValue: CodeValuePairType_Value_Optional;
  published
    property Code: Cardinal read FCode write FCode;
    property Value: CodeValuePairType_Value_Optional read FValue write FValue;
  end;

it will be generated as

<xs:complexType name="CodeValuePairType">
  <xs:sequence>
    <xs:element name="Code" type="xs:int"></xs:element>
    <xs:element name="Value" type="xs:string" minOccurs="0" maxOccurs="1"></xs:element>
  </xs:sequence>
</xs:complexType>

Note: we don’t generate minOccurs="1" maxOccurs="1" so

<xs:element name="Code" minOccurs="1" maxOccurs="1" type="xs:int"></xs:element>

will be generated as

<xs:element name="Code" type="xs:int"></xs:element>

Hey Evgeny,

That seems to work thanks!

Two small remarks:

Shouldn’t the approach I tried also work? I tried using the Service Builder, where you can manage custom attributes in the UI. When I let it genereate my interface for delphi I get the same declaration as the one I showed in my original post.

Second, where is the approach you present documented? I can see that it works, but can not yet understand why :grin: So I would like to read up on it, and see what other possibilities this technique has.

Hi,

    [ROCustom('minOccurs','1')]
    [ROCustom('maxOccurs','1')]

these attributes will work only for arrays.
for struct - they are ignored.

if you import your wsdl with ServiceBuilder, it will also create additional struct for simple type element that have minOccurs="0" maxOccurs="1"

Ok, that worked, but This leads to another problem. I have a class declared as follows:

  ContainerSystemInformationType = class(TROComplexType)
  private
    [...]
    function GetSystemInformation: CodeValuePairType_SystemInformation_Array;
  protected
    [...]
    property int_SystemInformation: CodeValuePairType_SystemInformation_Array read fSystemInformation;
  public
    [...]
  published
    [...]
    {$IFDEF RO_RTTI_Support}
    [ROCustom('soapname', 'SystemInformation')]
    {$ENDIF}
    property SystemInformation: CodeValuePairType_SystemInformation_Array read GetSystemInformation write fSystemInformation;
  end;

With CodeValuePairType_SystemInformation_Array declared as:

  {$IFNDEF RO_GenericArray}
  {$IFDEF RO_RTTI_Support}
  [ROCustom('minoccurs', '0')]
  [ROCustom('importedfromnamespace', 'http://www.stosag.nl/standard/2-1/CommonComponents')]
  [ROCustom('maxoccurs', '-1')]
  [ROCustom('anonymous', '1')]
  [ROCustom('soapname', 'CodeValuePairType')]
  [ROCustom('elementname', 'SystemInformation')]
  [RONamespace('http://www.stosag.nl/webservices/2016-1//CC-TransactionAndSystemInformation')]
  {$ENDIF}
  CodeValuePairType_SystemInformation_Array = class(TROArray)
[...]

This results in the following WSDL:

 <xs:complexType name="ContainerSystemInformationType">
    <xs:sequence>
       [...]
       <xs:element name="SystemInformation" type="tns:CodeValuePairType_SystemInformation_Array"/>
    </xs:sequence>
 </xs:complexType>

My problem is the CodeValuePairType_SystemInformation_Array datatype used as an intermediary. According to the standard I have to adhere to I should end up with a WSDL as follows:

<xs:complexType name="ContainerSystemInformationType">
    <xs:sequence>
        [...]          
        <xs:element name="SystemInformation" type="tns:CodeValuePairType" minOccurs="0" maxOccurs="unbounded">
    </xs:sequence>
 </xs:complexType>

I’ve tried, but failed to define my object in such a way that I end up with the WSDL following said standard.

can you confirm that you haven’t RO_GenericArray defined?

RO_GenericArray is OFF as far as I can tell.

Hi,

I have

<xs:complexType name="CodeValuePairType_SystemInformation_Array">
  <xs:sequence>
    <xs:element name="SystemInformation" minOccurs="0" maxOccurs="unbounded" type="tns:CodeValuePairType"/>
  </xs:sequence>
</xs:complexType>

this is for

  [ROCustom('IsSimpleTypeExtension','1')]
  CodeValuePairType_Value_Optional = class(TROComplexType)
  private
    FValue: string;
  published
    property Value: string read FValue write FValue;
  end;

  CodeValuePairType = class(TROComplexType)
  private
    FCode: Cardinal;
    FValue: CodeValuePairType_Value_Optional;
  published
    property Code: Cardinal read FCode write FCode;
    property Value: CodeValuePairType_Value_Optional read FValue write FValue;
  end;


  [ROCustom('minoccurs', '0')]
  [ROCustom('importedfromnamespace', 'http://www.stosag.nl/standard/2-1/CommonComponents')]
  [ROCustom('maxoccurs', '-1')]
  [ROCustom('anonymous', '1')]
  [ROCustom('soapname', 'CodeValuePairType')]
  [ROCustom('elementname', 'SystemInformation')]
  [RONamespace('http://www.stosag.nl/webservices/2016-1//CC-TransactionAndSystemInformation')]
  CodeValuePairType_SystemInformation_Array = class(TROArray<CodeValuePairType>);

  ContainerSystemInformationType = class(TROComplexType)
  private
    fSystemInformation: CodeValuePairType_SystemInformation_Array;
  protected
    property int_SystemInformation: CodeValuePairType_SystemInformation_Array read fSystemInformation;
  public
  published
    [ROCustom('soapname', 'SystemInformation')]
    property SystemInformation: CodeValuePairType_SystemInformation_Array read fSystemInformation write fSystemInformation;
  end;

Hi there,

Sorry for the delayed response, I have been unvailable for a few days.

The issue I have is that the systeminformation element is of the type CodeValuePairType_SystemInformation_Array, while it should be of the CodeValuePairType type with minoccurs and maxoccurs set directly on the systeminformation element.

The problem I have is that the standard defines a certain wsdl which is shared between different parties and should have the exact same structure :frowning: The additional array would break this.

Hi,

Remoting SDK will create this element as array.

for example, if original WSDL contains

<element name="ApexClassIds" nillable="true" minOccurs="0" maxOccurs="unbounded" type="xsd:string"/>

this item will be generated in Remoting SDK as

<xs:element name="ApexClassIds" type="tns:ID_ApexClassIds_Array" />
<xs:complexType name="ID_ApexClassIds_Array">
  <xs:sequence>
      <xs:element name="ApexClassIds" minOccurs="0" maxOccurs="unbounded" type="xs:string" />
  </xs:sequence>
</xs:complexType>

Can you retest generated soap request, if array is used here?