Jak uzyskać zagnieżdżone parametry complexType dla operacji z wsdl protokołu SOAP w języku C #
Mając WSDL i mając jedną oferowaną przez niego operację, chcę ją przeanalizować i pobrać parametry wejściowe dla tej operacji, ten przykład działa tylko wtedy, gdy nie ma zagnieżdżonych typów złożonych:
Jak przeanalizować plik xsd, który ma zagnieżdżone elementy (elementy i atrybuty complexType i simpleType)?
W tym celu działa:
http://www.dneonline.com/calculator.asmx?wsdl
A to oznacza, że zwraca dla wszystkich 4 operacji poprawne parametry (Add ma AddSoapIn z intA i intB ...)
ale w tym przypadku nie:
http://www.learnwebservices.com/services/hello?WSDL
Dostaje się tylko do HelloRequest dla SayHello i nie pobiera nazwy elementu z HelloRequest.
Powinno to zadziałać dla wszystkich, a nie konkretnych WSDL SOAP, mam na myśli ogólne analizowanie.
To jest odpowiednia część kodu:
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;
}
kiedy wywołuję getParams dla SayHello, wyświetla się w wierszu poleceń:

pierwszy debuguj z linii 49 (w kodzie poprzedniego komentarza;)), drugi z linii 70 i ostatni z linii 138 funkcji OutputElements.
Próbowałem też uzyskać complexType, w tym przypadku HelloRequest, gdy w linii 139 nie ma wartości null (childElement) i dodano jako parametr,
i przekształć go w typ złożony:
XmlSchemaComplexType complexTypeChild = sequence.Items[i] as XmlSchemaComplexType;
podobnie jak SayHello, rodzic HelloRequest jest przetwarzany i wywołuje go ponownie ta sama funkcja OutputElements z complexTypeChild, rekurencyjna
więc jeśli ma inne dziecko, będzie działać
ale complexTypeChild ma wartość null.
Okazało się, że OutputElements w ten sposób:
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;
}
zobacz 5 wierszy po
// if it has children
więc jeśli zostanie znaleziony, sprawdź, czy ma dzieci, również dodałem parametr / element nadrzędny do parametru, aby móc go użyć podczas tworzenia koperty, aby wywołać tę operację.
Odpowiedzi
Wziąłem WSDL i usunąłem sekcję schematu. Następnie uruchom xsd.exe w sekcji i przejdź do następujących klas języka C #
//------------------------------------------------------------------------------
// <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;
}
}
}
Więc teraz działa, problem polegał na tym, że rozwiązanie, z którego użyłem kodu, początkowo: tutaj
był faktycznie wykonany na zamówienie dla typu wsdl, z jednym głębokim poziomem complexTypes, i musiałem pracować dla KAŻDEGO wsdl, próbowałem teraz dla kilku, które mam i działa, ale być może znajdę przykład z niektórymi skomplikowane rzeczy, które nie będą działać, w takim przypadku wrócę tutaj i wyślę poprawiony kod.
W każdym razie rozwiązanie jest następujące, przynajmniej na razie, jak mówię, wydaje się, że działa dla dokumentów i rpc i mydła 1.1 i mydła 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;
}
To, biorąc pod uwagę JAKIEKOLWIEK przeanalizowane WSDL, zobacz kod początkowy / oryginalny posta, da operacji parametry do wywołania wraz z rodzicem dla każdego.