Comment obtenir des paramètres complexType imbriqués pour une opération à partir d'un wsdl SOAP en C #
Ayant un WSDL et étant donné une opération offerte par celui-ci, je veux l'analyser et récupérer les paramètres d'entrée pour cette opération, cet exemple ne fonctionne pour moi que lorsqu'il n'y a pas de types complexes imbriqués:
Comment analyser un fichier xsd qui a des éléments imbriqués (éléments et attributs complexType et simpleType)?
Pour cela, cela fonctionne:
http://www.dneonline.com/calculator.asmx?wsdl
Et cela signifie qu'il renvoie pour les 4 opérations les paramètres corrects (Add a AddSoapIn avec intA et intB ...)
mais pour cela ne:
http://www.learnwebservices.com/services/hello?WSDL
Il accède uniquement à HelloRequest pour SayHello et ne récupère pas l'élément Name de HelloRequest.
Cela devrait fonctionner pour tous les WSDL SOAP et non spécifiques, ce que je veux dire est une analyse générique.
Voici la partie pertinente du code:
public TheClient(string url) {
wsdlUrl = url;
ReadServiceDescription();
ServiceName = theService.Name;
}
...
void ReadServiceDescription()
{
try
{
XmlTextReader reader=new XmlTextReader (wsdlUrl);
ServiceDescription service=
ServiceDescription.Read(reader);
theService = service;
_services.Add(service);
}
catch (Exception e)
{
throw e;
}
}
private static List<Tuple<string, string>> getParams(string methodName, XmlSchema schemaXML)
{
List<Tuple<string, string>> parameters = new List<Tuple<string, string>>();
ServiceDescription serviceDescription = theService;
XmlSchema xmlSchema;
WebClient client = new WebClient(); ;
//Drill down into the WSDL's complex types to list out the individual schema elements
//and their data types
Types types = serviceDescription.Types;
if (schemaXML != null)
{
xmlSchema = schemaXML;
} else
{
xmlSchema = types.Schemas[0];
}
foreach (object item in xmlSchema.Items)
{
XmlSchemaElement schemaElement = item as XmlSchemaElement;
XmlSchemaComplexType complexType = item as XmlSchemaComplexType;
if (schemaElement != null && methodName == schemaElement.Name)
{
Console.Out.WriteLine("Schema Element: {0}", schemaElement.Name);
XmlSchemaType schemaType = schemaElement.SchemaType;
XmlSchemaComplexType schemaComplexType = schemaType as XmlSchemaComplexType;
if (schemaComplexType != null)
{
XmlSchemaParticle particle = schemaComplexType.Particle;
XmlSchemaSequence sequence = particle as XmlSchemaSequence;
if (sequence != null)
{
foreach (XmlSchemaElement childElement in sequence.Items)
{
Console.Out.WriteLine(" Element/Type: {0}:{1}", childElement.Name, childElement.SchemaTypeName.Name);
parameters.Add(new Tuple<string, string>(childElement.Name, childElement.SchemaTypeName.Name));
}
}
}
}
else if (complexType != null && complexType.Name == methodName)
{
Console.Out.WriteLine("Complex Type: {0}", complexType.Name);
List<Tuple<string, string>> moreparams = OutputElements(complexType.Particle);
if(moreparams != null && moreparams.Count !=0)
{
parameters.AddRange(moreparams);
}
}
//Console.Out.WriteLine();
}
// Loop through all detected imports in the main schema
List<Tuple<string, string>> importparameters = ImportIncludedSchemasRecursively(wsdlUrl, methodName, xmlSchema);
if (importparameters != null && importparameters.Count != 0)
{
parameters.AddRange(importparameters);
}
return parameters;
}
private static List<Tuple<string, string>> ImportIncludedSchemasRecursively(string mainWsdlUrl, string methodName, XmlSchema currentWsdlSchema)
{
List<Tuple<string, string>> parameters = new List<Tuple<string, string>>();
foreach (XmlSchemaObject externalSchema in currentWsdlSchema.Includes)
{
// Read each external schema into a schema object
if (externalSchema is XmlSchemaImport)
{
Uri baseUri = new Uri(mainWsdlUrl);
Uri schemaUri = new Uri(baseUri, ((XmlSchemaExternal)externalSchema).SchemaLocation);
WebClient http = new WebClient();
Stream schemaStream = http.OpenRead(schemaUri);
System.Xml.Schema.XmlSchema schema = XmlSchema.Read(schemaStream, null);
List<Tuple<string, string>> complexparams = getParams(methodName, schema);
if (complexparams != null && complexparams.Count != 0)
{
parameters.AddRange(complexparams);
}
List<Tuple<string, string>> morecomplexparams = ImportIncludedSchemasRecursively(mainWsdlUrl.ToString(), methodName, schema);
if (morecomplexparams != null && morecomplexparams.Count != 0)
{
parameters.AddRange(morecomplexparams);
}
}
}
return parameters.Distinct().ToList();
}
private static List<Tuple<string, string>> OutputElements(XmlSchemaParticle particle)
{
List<Tuple<string, string>> parameters = new List<Tuple<string, string>>();
XmlSchemaSequence sequence = particle as XmlSchemaSequence;
XmlSchemaChoice choice = particle as XmlSchemaChoice;
XmlSchemaAll all = particle as XmlSchemaAll;
if (sequence != null)
{
for (int i = 0; i < sequence.Items.Count; i++)
{
XmlSchemaElement childElement = sequence.Items[i] as XmlSchemaElement;
XmlSchemaSequence innerSequence = sequence.Items[i] as XmlSchemaSequence;
XmlSchemaChoice innerChoice = sequence.Items[i] as XmlSchemaChoice;
XmlSchemaAll innerAll = sequence.Items[i] as XmlSchemaAll;
Console.Out.WriteLine("111 child: {0}", childElement.Name);
if (childElement != null)
{
parameters.Add(new Tuple<string, string>(childElement.Name, childElement.SchemaTypeName.Name));
}
else {
List<Tuple<string, string>> moreparams = OutputElements(sequence.Items[i] as XmlSchemaParticle);
if (moreparams != null && moreparams.Count != 0)
{
parameters.AddRange(moreparams);
}
}
}
return parameters;
}
else if (choice != null)
{
Console.Out.WriteLine(" Choice");
for (int i = 0; i < choice.Items.Count; i++)
{
XmlSchemaElement childElement = choice.Items[i] as XmlSchemaElement;
XmlSchemaSequence innerSequence = choice.Items[i] as XmlSchemaSequence;
XmlSchemaChoice innerChoice = choice.Items[i] as XmlSchemaChoice;
XmlSchemaAll innerAll = choice.Items[i] as XmlSchemaAll;
Console.Out.WriteLine("222 child: {0}", childElement.Name);
if (childElement != null)
{
parameters.Add(new Tuple<string, string>(childElement.Name, childElement.SchemaTypeName.Name));
}
else
{
List<Tuple<string, string>> moreparams = OutputElements(choice.Items[i] as XmlSchemaParticle);
if (moreparams != null && moreparams.Count != 0)
{
parameters.AddRange(moreparams);
}
}
}
return parameters;
}
else if (all != null)
{
for (int i = 0; i < all.Items.Count; i++)
{
XmlSchemaElement childElement = all.Items[i] as XmlSchemaElement;
XmlSchemaSequence innerSequence = all.Items[i] as XmlSchemaSequence;
XmlSchemaChoice innerChoice = all.Items[i] as XmlSchemaChoice;
XmlSchemaAll innerAll = all.Items[i] as XmlSchemaAll;
Console.Out.WriteLine("333 child: {0}", childElement.Name);
if (childElement != null)
{
parameters.Add(new Tuple<string, string>(childElement.Name, childElement.SchemaTypeName.Name));
}
else
{
List<Tuple<string, string>> moreparams = OutputElements(all.Items[i] as XmlSchemaParticle);
if (moreparams != null && moreparams.Count != 0)
{
parameters.AddRange(moreparams);
}
}
}
return parameters;
}
return parameters;
}
lorsque j'appelle getParams pour SayHello, il s'affiche sur la ligne de commande:

premier débogage à partir de la ligne 49 (dans le code du commentaire précédent;)), deuxième à partir de la ligne 70 et dernier à partir de la ligne 138 de la fonction OutputElements.
J'ai également essayé d'obtenir le complexType, dans ce cas HelloRequest, quand la ligne 139 n'est pas nulle (childElement) et ajoutée en tant que paramètre,
et transformez-le en type complexe:
XmlSchemaComplexType complexTypeChild = sequence.Items[i] as XmlSchemaComplexType;
similaire au SayHello, le parent de HelloRequest est traité, et appelle à nouveau la même fonction OutputElements avec complexTypeChild, récursif
alors si un autre enfant travaillera
mais complexTypeChild est nul.
J'ai changé les OutputElements comme ceci:
private static List<Tuple<string, string, string>> OutputElements(XmlSchemaParticle particle, string parentName)
{
List<Tuple<string, string, string>> parameters = new List<Tuple<string, string, string>>();
XmlSchemaSequence sequence = particle as XmlSchemaSequence;
XmlSchemaChoice choice = particle as XmlSchemaChoice;
XmlSchemaAll all = particle as XmlSchemaAll;
if (sequence != null)
{
for (int i = 0; i < sequence.Items.Count; i++)
{
XmlSchemaElement childElement = sequence.Items[i] as XmlSchemaElement;
XmlSchemaSequence innerSequence = sequence.Items[i] as XmlSchemaSequence;
XmlSchemaChoice innerChoice = sequence.Items[i] as XmlSchemaChoice;
XmlSchemaAll innerAll = sequence.Items[i] as XmlSchemaAll;
if (childElement != null)
{
parameters.Add(new Tuple<string, string, string>(childElement.Name, childElement.SchemaTypeName.Name, parentName));
// if it has children
List<Tuple<string, string, string>> moreparams = getParams(childElement.SchemaTypeName.Name, null);
if (moreparams != null && moreparams.Count != 0)
{
parameters.AddRange(moreparams);
}
}
else {
List<Tuple<string, string, string>> moreparams = OutputElements(sequence.Items[i] as XmlSchemaParticle, parentName);
if (moreparams != null && moreparams.Count != 0)
{
parameters.AddRange(moreparams);
}
}
}
return parameters;
}
else if (choice != null)
{
Console.Out.WriteLine(" Choice");
for (int i = 0; i < choice.Items.Count; i++)
{
XmlSchemaElement childElement = choice.Items[i] as XmlSchemaElement;
XmlSchemaSequence innerSequence = choice.Items[i] as XmlSchemaSequence;
XmlSchemaChoice innerChoice = choice.Items[i] as XmlSchemaChoice;
XmlSchemaAll innerAll = choice.Items[i] as XmlSchemaAll;
if (childElement != null)
{
parameters.Add(new Tuple<string, string, string>(childElement.Name, childElement.SchemaTypeName.Name, parentName));
}
else
{
List<Tuple<string, string, string>> moreparams = OutputElements(choice.Items[i] as XmlSchemaParticle, parentName);
if (moreparams != null && moreparams.Count != 0)
{
parameters.AddRange(moreparams);
}
}
}
return parameters;
}
else if (all != null)
{
for (int i = 0; i < all.Items.Count; i++)
{
XmlSchemaElement childElement = all.Items[i] as XmlSchemaElement;
XmlSchemaSequence innerSequence = all.Items[i] as XmlSchemaSequence;
XmlSchemaChoice innerChoice = all.Items[i] as XmlSchemaChoice;
XmlSchemaAll innerAll = all.Items[i] as XmlSchemaAll;
if (childElement != null)
{
parameters.Add(new Tuple<string, string, string>(childElement.Name, childElement.SchemaTypeName.Name, parentName));
}
else
{
List<Tuple<string, string, string>> moreparams = OutputElements(all.Items[i] as XmlSchemaParticle, parentName);
if (moreparams != null && moreparams.Count != 0)
{
parameters.AddRange(moreparams);
}
}
}
return parameters;
}
return parameters;
}
voir les 5 lignes après
// if it has children
donc si trouvé, vérifiez si a des enfants, j'ai également ajouté le paramètre / élément parent au paramètre afin que je puisse l'utiliser lors de la création de l'enveloppe avec laquelle appeler cette opération.
Réponses
J'ai pris le WSDL et supprimé la section de schéma. Ensuite, exécutez xsd.exe dans la section et accédez aux classes c # suivantes
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System.Xml.Serialization;
//
// This source code was auto-generated by xsd, Version=4.0.30319.33440.
//
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.33440")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://learnwebservices.com/services/hello")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="http://learnwebservices.com/services/hello", IsNullable=false)]
public partial class SayHello {
private helloRequest helloRequestField;
/// <remarks/>
public helloRequest HelloRequest {
get {
return this.helloRequestField;
}
set {
this.helloRequestField = value;
}
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.33440")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://learnwebservices.com/services/hello")]
public partial class helloRequest {
private string nameField;
/// <remarks/>
public string Name {
get {
return this.nameField;
}
set {
this.nameField = value;
}
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.33440")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://learnwebservices.com/services/hello")]
public partial class helloResponse {
private string messageField;
/// <remarks/>
public string Message {
get {
return this.messageField;
}
set {
this.messageField = value;
}
}
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.33440")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://learnwebservices.com/services/hello")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="http://learnwebservices.com/services/hello", IsNullable=false)]
public partial class SayHelloResponse {
private helloResponse helloResponseField;
/// <remarks/>
public helloResponse HelloResponse {
get {
return this.helloResponseField;
}
set {
this.helloResponseField = value;
}
}
}
Alors maintenant, cela fonctionne, le problème était que la solution à partir de laquelle j'ai utilisé le code, initialement: ici
a été en fait fait sur mesure pour un type de wsdl, avec un niveau profond de complexTypes, et j'avais besoin de travailler pour N'IMPORTE QUEL wsdl, j'en ai maintenant essayé quelques-uns et cela fonctionne mais il se peut que je trouve un exemple avec certains des trucs complexes qui ne fonctionneront pas, dans ce cas je reviendrai ici et posterai le code corrigé.
Quoi qu'il en soit, la solution est la suivante, du moins pour le moment, comme je le dis, cela semble fonctionner pour document et rpc et soap 1.1 et soap 1.2 wsdls:
private static List<Tuple<string, string, string>> getParams(string methodName, XmlSchema schemaXML)
{
List<Tuple<string, string, string>> parameters = new List<Tuple<string, string, string>>();
ServiceDescription serviceDescription = theService;
XmlSchema xmlSchema;
WebClient client = new WebClient(); ;
//Drill down into the WSDL's complex types to list out the individual schema elements
//and their data types
Types types = serviceDescription.Types;
if (schemaXML != null)
{
xmlSchema = schemaXML;
} else
{
xmlSchema = types.Schemas[0];
}
foreach (object item in xmlSchema.Items)
{
XmlSchemaElement schemaElement = item as XmlSchemaElement;
XmlSchemaComplexType complexType = item as XmlSchemaComplexType;
if (schemaElement != null && methodName == schemaElement.Name)
{
Console.Out.WriteLine("Schema Element: {0}", schemaElement.Name);
XmlSchemaType schemaType = schemaElement.SchemaType;
XmlSchemaComplexType schemaComplexType = schemaType as XmlSchemaComplexType;
if (schemaComplexType != null)
{
XmlSchemaParticle particle = schemaComplexType.Particle;
XmlSchemaSequence sequence = particle as XmlSchemaSequence;
if (sequence != null)
{
foreach (XmlSchemaElement childElement in sequence.Items)
{
parameters.Add(new Tuple<string, string, string>(childElement.Name, childElement.SchemaTypeName.Name, schemaElement.Name));
}
}
}
}
else if (complexType != null && complexType.Name == methodName)
{
Console.Out.WriteLine("Complex Type: {0}", complexType.Name);
List<Tuple<string, string, string>> moreparams = OutputElements(complexType.Particle, complexType.Name);
if(moreparams != null && moreparams.Count !=0)
{
parameters.AddRange(moreparams);
}
}
}
// Loop through all detected imports in the main schema
List<Tuple<string, string, string>> importparameters = ImportIncludedSchemasRecursively(wsdlUrl, methodName, xmlSchema);
if (importparameters != null && importparameters.Count != 0)
{
parameters.AddRange(importparameters);
}
return parameters;
}
private static List<Tuple<string, string, string>> ImportIncludedSchemasRecursively(string mainWsdlUrl, string methodName, XmlSchema currentWsdlSchema)
{
List<Tuple<string, string, string>> parameters = new List<Tuple<string, string, string>>();
foreach (XmlSchemaObject externalSchema in currentWsdlSchema.Includes)
{
// Read each external schema into a schema object
if (externalSchema is XmlSchemaImport)
{
Uri baseUri = new Uri(mainWsdlUrl);
Uri schemaUri = new Uri(baseUri, ((XmlSchemaExternal)externalSchema).SchemaLocation);
WebClient http = new WebClient();
Stream schemaStream = http.OpenRead(schemaUri);
System.Xml.Schema.XmlSchema schema = XmlSchema.Read(schemaStream, null);
List<Tuple<string, string, string>> complexparams = getParams(methodName, schema);
if (complexparams != null && complexparams.Count != 0)
{
parameters.AddRange(complexparams);
}
List<Tuple<string, string, string>> morecomplexparams = ImportIncludedSchemasRecursively(mainWsdlUrl.ToString(), methodName, schema);
if (morecomplexparams != null && morecomplexparams.Count != 0)
{
parameters.AddRange(morecomplexparams);
}
}
}
return parameters.Distinct().ToList();
}
private static List<Tuple<string, string, string>> OutputElements(XmlSchemaParticle particle, string parentName)
{
List<Tuple<string, string, string>> parameters = new List<Tuple<string, string, string>>();
XmlSchemaSequence sequence = particle as XmlSchemaSequence;
XmlSchemaChoice choice = particle as XmlSchemaChoice;
XmlSchemaAll all = particle as XmlSchemaAll;
if (sequence != null)
{
for (int i = 0; i < sequence.Items.Count; i++)
{
XmlSchemaElement childElement = sequence.Items[i] as XmlSchemaElement;
XmlSchemaSequence innerSequence = sequence.Items[i] as XmlSchemaSequence;
XmlSchemaChoice innerChoice = sequence.Items[i] as XmlSchemaChoice;
XmlSchemaAll innerAll = sequence.Items[i] as XmlSchemaAll;
if (childElement != null)
{
parameters.Add(new Tuple<string, string, string>(childElement.Name, childElement.SchemaTypeName.Name, parentName));
// if it has children
List<Tuple<string, string, string>> moreparams = getParams(childElement.SchemaTypeName.Name, null);
if (moreparams != null && moreparams.Count != 0)
{
parameters.AddRange(moreparams);
}
}
else {
List<Tuple<string, string, string>> moreparams = OutputElements(sequence.Items[i] as XmlSchemaParticle, parentName);
if (moreparams != null && moreparams.Count != 0)
{
parameters.AddRange(moreparams);
}
}
}
return parameters;
}
else if (choice != null)
{
Console.Out.WriteLine(" Choice");
for (int i = 0; i < choice.Items.Count; i++)
{
XmlSchemaElement childElement = choice.Items[i] as XmlSchemaElement;
XmlSchemaSequence innerSequence = choice.Items[i] as XmlSchemaSequence;
XmlSchemaChoice innerChoice = choice.Items[i] as XmlSchemaChoice;
XmlSchemaAll innerAll = choice.Items[i] as XmlSchemaAll;
if (childElement != null)
{
parameters.Add(new Tuple<string, string, string>(childElement.Name, childElement.SchemaTypeName.Name, parentName));
}
else
{
List<Tuple<string, string, string>> moreparams = OutputElements(choice.Items[i] as XmlSchemaParticle, parentName);
if (moreparams != null && moreparams.Count != 0)
{
parameters.AddRange(moreparams);
}
}
}
return parameters;
}
else if (all != null)
{
for (int i = 0; i < all.Items.Count; i++)
{
XmlSchemaElement childElement = all.Items[i] as XmlSchemaElement;
XmlSchemaSequence innerSequence = all.Items[i] as XmlSchemaSequence;
XmlSchemaChoice innerChoice = all.Items[i] as XmlSchemaChoice;
XmlSchemaAll innerAll = all.Items[i] as XmlSchemaAll;
if (childElement != null)
{
parameters.Add(new Tuple<string, string, string>(childElement.Name, childElement.SchemaTypeName.Name, parentName));
}
else
{
List<Tuple<string, string, string>> moreparams = OutputElements(all.Items[i] as XmlSchemaParticle, parentName);
if (moreparams != null && moreparams.Count != 0)
{
parameters.AddRange(moreparams);
}
}
}
return parameters;
}
return parameters;
}
Ceci, étant donné N'IMPORTE QUEL wsdl analysé, voir le code du message initial / original pour cela, donnera pour une opération les paramètres pour l'appeler avec le parent pour chacun.