I am completely new to web services, but not new to Delphi.
I am importing a WSDL file into Delphi 2010 with the "WSDL Importer" wizard. The WSDL file contains some "attributeGroup" tags which Delphi completely ignores, which is presumably a bug, although I haven't yet found an entry on Quality Central for this issue, only mentions in forums like here and here.
My question has several parts:
- What is the best workaround?
- I have written a Python script to format the WSDL file such that all references to attributeGroup tags are replaced with the declaration of the attributes defined in the attributeGroups; in other words, flattening the references. The output is successfully imported into Delphi via the "WSDL importer" wizard, and looks correct, but I have yet to test whether the messages constructed via this new WSDL file will work correctly. Is this strategy likely to be viable, or should I quit now and move onto something else more productive?
Update
Based on my experiences, and the answers in this question, I decided to go the wrapper route with a C# console application that eats JSON input data and outputs JSON reply data. A Delphi app d开发者_运维知识库rives the C# app. The SOAP part of the whole thing is now effortless, and "just works" in C#.NET, and the rest of the functionality is handled well by Delphi. I would recommend this route to anyone else with similar problems. I did try exporting a C# SOAP assembly as a COM library, and connecting to that from Delphi, but it became very complex, because the SOAP specification in my particular app is large and somewhat complex.
Ok, this one took a while.
According to this post, there are certain tags that the .NET wsdl.exe tool just won't recognize when importing a wsdl file. According to MSDN:
attributeGroup: Ignored. DataContractSerializer does not support use of xs:group, xs:attributeGroup, and xs:attribute. These declarations are ignored as children of xs:schema, but cannot be referenced from within complexType or other supported constructs.
This behaviour is also described (albeit in a very hard-to-understand manner) on one of the MSDN blogs. In my specific case, the particular part of the wsdl file causing the problem looks like this:
<xs:complexType name="PhonesType">
<xs:annotation>
<xs:documentation xml:lang="en">Provides detailed phone information.</ xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="Phone">
<xs:annotation>
<xs:documentation xml:lang="en">Used to pass detailed phone information.</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attributeGroup ref="TelephoneInfoGroup"/>
<xs:attributeGroup ref="ID_OptionalGroup">
<xs:annotation>
<xs:documentation xml:lang="en">The ID attribute in this group is a unique identifying value assigned by the creating system and may be used to reference a primary-key value within a database or in a particular implementation.</xs:documentation>
</xs:annotation>
</xs:attributeGroup>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
It seems that the <xs:attributeGroup ref="TelephoneInfoGroup"/>
is being ignored by the .NET wsdl.exe tool, just like it was being ignored by the Delphi wsdl importer. In such a situation, where importing fails in both Delphi and .NET, the wsdl file probably has to be changed, and that means I will have to use my home-made python ref-flattener after all.
We had a similar problem with Delphi 2009 and a standard Soap service (CRM). It was not related to attributeGroup. We found so many incompatibilities that we finally decided to use a small C# application as a proxy for the real .Net based service.
I was the poster of the first reference you give. I think I found out that this bug has never been fixed.
I later posted another question on the Embarcadero Developer Network where Nick Hodges said that
We are concentrating on client development [...] if you are looking to build SOAP servers, then I'd suggest that you also give Delphi Prism a look.
We decided to switch to C# for development of our SOAP servers. I decided to let the service talk to a database, which is then accessed by our Delphi application.
Later I ran into problems with client development under Delphi as well, so we're doing that in C#, too. This time the C# class is com visible and can be accessed from Delphi. Seems to work fine.
Regards, Miel.
The Delphi WSDL importer can't handle <xsd:attributeGroup ref="...">
elements, but you can replace those with the actual attributes that are referenced, which the importer can deal with.
Below is a PowerShell script that does this replacement.
The script is unpolished. It's just what I created for my own needs. It may work for you too, or at least it should give you a starting point.
$xsdPath = "E:\scratch\InputFile.wsdl"
# Note: Must be full path.
$outPath = "E:\scratch\OutputFile.wsdl"
$xsd = [xml](gc $xsdPath)
$ns = @{xsd="http://www.w3.org/2001/XMLSchema"}
$attrGroupDefs = $xsd |
Select-Xml -Namespace $ns -XPath "//xsd:schema/xsd:attributeGroup" |
select -ExpandProperty Node
$attrGroupRefs = $xsd |
Select-Xml -Namespace $ns -XPath "//xsd:complexType/xsd:attributeGroup" |
select -ExpandProperty Node
$attrGroupRefs | % {
# the thing to be replaced
$ref = $_
$refParent = $ref.ParentNode
$namespace, $name = $_.ref -split ":"
$attrs = $attrGroupDefs | ? name -eq $name | select -ExpandProperty attribute
# remove the reference
$refParent.RemoveChild($ref)
# add the actual definitions
$attrs | % {
$newNode = $_.CloneNode($true)
$refParent.AppendChild($newNode)
}
}
$xsd.Save($outPath)
精彩评论