So erhalten Sie verschachtelte complexType-Parameter für eine Operation von einer SOAP-wsdl in c #

Nov 19 2020

Mit einer WSDL und einer von ihr angebotenen Operation möchte ich sie analysieren und die Eingabeparameter für diese Operation abrufen. Dieses Beispiel funktioniert nur, wenn keine verschachtelten komplexen Typen vorhanden sind:

Wie analysiere ich eine xsd-Datei mit verschachtelten Elementen (complexType- und simpleType-Elemente und -Attribute)?

Dafür funktioniert es:

http://www.dneonline.com/calculator.asmx?wsdl

Und das bedeutet, dass für alle 4 Operationen die richtigen Parameter zurückgegeben werden (Add hat AddSoapIn mit intA und intB ...)

aber dafür nicht:

http://www.learnwebservices.com/services/hello?WSDL

Es gelangt nur zur HelloRequest für SayHello und ruft das Element Name nicht von HelloRequest ab.

Dies sollte für alle und nicht für bestimmte SOAP-WSDLs funktionieren. Ich meine, es handelt sich um eine generische Analyse.

Dies ist der relevante Teil des Codes:

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;
}

Wenn ich getParams für SayHello aufrufe, wird es in der Befehlszeile angezeigt:

erstes Debugging aus Zeile 49 (im Code des vorherigen Kommentars;)), zweites aus Zeile 70 und letztes aus Zeile 138 der OutputElements-Funktion.

Ich habe auch versucht, den complexType, in diesem Fall HelloRequest, abzurufen, wenn in Zeile 139 nicht null (childElement) steht und als param hinzugefügt wird.

und transformiere es in einen komplexen Typ:

XmlSchemaComplexType complexTypeChild = sequence.Items[i] as XmlSchemaComplexType;

Ähnlich wie beim SayHello wird das übergeordnete Element von HelloRequest verarbeitet und ruft erneut dieselbe Funktion OutputElements mit complexTypeChild auf, rekursiv

Also, wenn ein anderes Kind hat, wird es funktionieren

aber complexTypeChild ist null.

Ich habe die OutputElements wie folgt verändert:

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;
}

siehe die 5 Zeilen danach

// if it has children

Wenn also gefunden, überprüfen Sie, ob Kinder vorhanden sind. Außerdem habe ich den übergeordneten Parameter / das übergeordnete Element zum Parameter hinzugefügt, damit ich ihn beim Erstellen des Umschlags verwenden kann, mit dem diese Operation aufgerufen werden soll.

Antworten

jdweng Nov 19 2020 at 18:39

Ich nahm die WSDL und entfernte den Schemaabschnitt. Führen Sie dann die Datei xsd.exe für den Abschnitt aus und führen Sie die folgenden c # -Klassen aus

//------------------------------------------------------------------------------
// <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;
        }
    }
}
whiteadi Nov 24 2020 at 15:20

Jetzt funktioniert es also, das Problem war, dass die Lösung, aus der ich den Code verwendet habe, anfangs: hier

wurde tatsächlich für eine Art von wsdl mit einer tiefen Ebene von complexTypes angepasst, und ich musste für JEDE wsdl arbeiten. Ich habe jetzt einige davon ausprobiert und es funktioniert, aber es könnte sein, dass ich mit einigen ein Beispiel finden werde komplexe Sachen, die nicht funktionieren werden, in diesem Fall werde ich hierher zurückkommen und den festen Code posten.

Wie auch immer, die Lösung ist folgende, zumindest für den Moment, wie ich sage, scheint es für document und rpc und soap 1.1 und soap 1.2 wsdls zu funktionieren:

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;
}

Dies, vorausgesetzt, JEDE analysierte wsdl, siehe den Code des ursprünglichen / ursprünglichen Beitrags, gibt für eine Operation die Parameter an, mit denen sie zusammen mit dem übergeordneten Element für jede Operation aufgerufen werden soll.