pavanarya

Let us share the knowledge

WSDL(Web Service Definition Language) Parser

with 4 comments

Hi,

In this post i want to write an article on how to parse the WSDL file to get the required information from it.

How a web service actually works

I am just giving an overview on how a webservice is actually created and used .

1.We create a webservice with some webmethods and the webservice is exposed to external world using an url(.asmx file).

2. So whenever a consumer wants to make use of the webservice, initially he is supposed to get the wsdl file of that webservice.

3.Using that wsdl file, he is supposed to create a proxy class for the web service.

4. A proxy class is nothing but a dummy class which contains dummy methods that are present inside our actual web service.

5. So whenever we want to call a particular method inside the webservice, we actually call the method present inside the proxy class which takes care of the call to the webservice.

Thus proxy class and wsdl plays an important role in the consumption of the webservice.

Overview of wsdl

WSDL is nothing but a xml document that represents the information about the webservices like protocol that webservice uses, methods present, their return types and parameters they accept.

<definitions>
<types>
It contains info about parameters , return types of webmethods
</types>

<message>
  It contains info about methods and it refers to types
</message>

<portType>
  it contains info about set of operations and it refers to messages
</portType>

<binding>
  it refers to protocol used like http & soap . This refers to porttypes
</binding>

<service>
it contains info about the web service url.
</service>
</definitions>

We can go through this site for wsdl tutorials.

My Web Service code
This the web service code i am using in this example.
I am having two web methods AddResults and HelloWorld.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;

namespace SOAPHEADEREXAMPLE
{
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
    [System.Web.Script.Services.ScriptService]
    public class WebService1 : System.Web.Services.WebService
    {
        [WebMethod]
        public string AddResults(string a,string b)
        {
            int addResult = Convert.ToInt32(a) + Convert.ToInt32(b);
            return addResult.ToString();
        }
        [WebMethod]
        public Pavan HelloWorld()
        {
            Pavan p = new Pavan();
            return p;
        }
    }
     public class Pavan
     {
        string name;
     }
}

WSDL generated for my webservice

<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="http://tempuri.org/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://tempuri.org/">


  <wsdl:types>
    <s:schema elementFormDefault="qualified" targetNamespace="http://tempuri.org/">
      <s:element name="AddResults">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="a" type="s:string"/>
            <s:element minOccurs="0" maxOccurs="1" name="b" type="s:string"/>
          </s:sequence>
        </s:complexType>
      </s:element>
      <s:element name="AddResultsResponse">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="AddResultsResult" type="s:string"/>
          </s:sequence>
        </s:complexType>
      </s:element>
      <s:element name="HelloWorld">
        <s:complexType/>
      </s:element>
      <s:element name="HelloWorldResponse">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="HelloWorldResult" type="tns:Pavan"/>
          </s:sequence>
        </s:complexType>
      </s:element>
      <s:complexType name="Pavan"/>
    </s:schema>
  </wsdl:types>


  <wsdl:message name="AddResultsSoapIn">
    <wsdl:part name="parameters" element="tns:AddResults"/>
  </wsdl:message>
  <wsdl:message name="AddResultsSoapOut">
    <wsdl:part name="parameters" element="tns:AddResultsResponse"/>
  </wsdl:message>
  <wsdl:message name="HelloWorldSoapIn">
    <wsdl:part name="parameters" element="tns:HelloWorld"/>
  </wsdl:message>
  <wsdl:message name="HelloWorldSoapOut">
    <wsdl:part name="parameters" element="tns:HelloWorldResponse"/>
  </wsdl:message>

  <wsdl:portType name="WebService1Soap">
    <wsdl:operation name="AddResults">
      <wsdl:input message="tns:AddResultsSoapIn"/>
      <wsdl:output message="tns:AddResultsSoapOut"/>
    </wsdl:operation>
    <wsdl:operation name="HelloWorld">
      <wsdl:input message="tns:HelloWorldSoapIn"/>
      <wsdl:output message="tns:HelloWorldSoapOut"/>
    </wsdl:operation>
  </wsdl:portType>

  <wsdl:binding name="WebService1Soap12" type="tns:WebService1Soap">
    <soap12:binding transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="AddResults">
      <soap12:operation soapAction="http://tempuri.org/AddResults" style="document"/>
      <wsdl:input>
        <soap12:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap12:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="HelloWorld">
      <soap12:operation soapAction="http://tempuri.org/HelloWorld" style="document"/>
      <wsdl:input>
        <soap12:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap12:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>


  <wsdl:service name="WebService1">
    <wsdl:port name="WebService1Soap" binding="tns:WebService1Soap">
      <soap:address location="http://localhost:1525/WebService1.asmx"/>
    </wsdl:port>
  </wsdl:service>

</wsdl:definitions>

So when we are trying to parse the WSDL we are supposed to follow bottom up approach in order to get the required information.

Now let us try to get the webservice information from above wsdl.
Service: It represents the name of the web service and also it contains name of the port and name of the binding along with the url of the webservice.
So we got the name of the web service :)

Binding: It contains tag which specifies the web method present inside our web service.
So we got the names of the web methods.

PortTypes: It contains the info about the messages ie InputMessage and OutPutMessage. Inputmessage represents parameters and outputmessages represent return type. From the method names we got in the binding tag we can retrieve messages names for input and output.

messages: Messages contains a tag called which contains an attribute called element which refers to .

Types: Types contains a tag called element with the name that we got in the messages.

Parsing WSDL

This is the class that is used to store the information about the webservice that we got from wsdl.

class OperationInputOutputParams
    {
        public string ClassName { set; get; }
        public string MethodName { set; get; }
        public string ReturnType { set; get; }
        public Dictionary<string, string> Parameters { set; get; }
    }

In the below code we are trying to load the wsdl document into the XMLReader.

1.ServiceDescription — It represents the complete wsdl document.
2.BindingCollection class– It represents all the info present inside Binding tag.
3. PortTypeColelction — It represents all the info present inside PortType tag
4. MessageColelction — it represents all the Message tags.
5. Types class — represents all the info present inside Types tag.
6. XmlSchema — represents the info present inside present inside Types tag.

        ServiceDescription serviceDescription = null;
        BindingCollection bindColl;
        PortTypeCollection portTypColl;
        MessageCollection msgColl;
        Types typs;
        XmlSchemas _schemas;
        
        public Program()
        {
            XmlReader reader = new XmlTextReader(@"http://localhost:1525/WebService1.asmx?wsdl");
             serviceDescription = ServiceDescription.Read(reader);
             bindColl = serviceDescription.Bindings;
             portTypColl = serviceDescription.PortTypes;
             msgColl = serviceDescription.Messages;
             typs = serviceDescription.Types;
             _schemas = typs.Schemas;
        }

In the below code i am trying to parse the wsdl by using the ServiceDescription class object which actually contains wsdl document.

1.Initially we are looping on Service and then we are trying to loop on all the ports that were associated with the service.

2. Now we are retrieving BindingName for each Port present inside Services and then retrieving the Binding using that bindingname and BindingCollection we got from service description.

3.Now we can get the PortType information for the bindingname we got in above step.

4.Now we can loop on all the operations present inside PortTypes.

5.Now for each Operation we can get the messages(OperationMessageCollection)

6. OperationMessageColelction represents both input and output messages associated with the opeartion present inside .

public List<OperationInputOutputParams> returnOperationsParameters()
        {
            List<OperationInputOutputParams> lst = new List<OperationInputOutputParams>();

            foreach (Service ser in serviceDescription.Services)
            {
                String webServiceNmae = ser.Name.ToString();
                foreach (Port port in ser.Ports)
                {
                    string portName = port.Name;
                    string binding = port.Binding.Name;
                    Binding bind = bindColl[binding];

                    PortType portTyp = portTypColl[bind.Type.Name];

                    foreach (Operation op in portTyp.Operations)
                    {
                        OperationMessageCollection opMsgColl = op.Messages;
                        OperationInput opInput = opMsgColl.Input;
                        OperationOutput opOutput = opMsgColl.Output;
                        string inputMsg = opInput.Message.Name;
                        string outputMsg = opOutput.Message.Name;

                        Message msgInput = msgColl[inputMsg];
                       Dictionary<string, string> InputParam= parseMessageAndReturnParameters(msgInput);

                        Message msgOutput = msgColl[outputMsg];
                        Dictionary<string, string> OutputParams = parseMessageAndReturnParameters(msgOutput);

                        string operationName = op.Name;
                        OperationInputOutputParams operObj = new OperationInputOutputParams();
                        operObj.ClassName = webServiceNmae;
                        operObj.MethodName = operationName;
                        operObj.Parameters = InputParam;
                        operObj.ReturnType=OutputParams.Values.ToArray<string>()[0];
                        lst.Add(operObj);
                    }
                }
            }
            return lst;
        }

In the below method parseMessageAndReturnParameters we are passing Message and from that we are trying to retrieve the parameters and return types information.

1.Each Message contains a tag called parts and it contains an attribute called elements. This element is the name of the Element tag present inside present inside .

2. So with the element name we got from messages we can get tag inside .

3. From this tag we can get (XmlSchemaComplexType ).

4. From the (XmlSchemaComplexType ) we can get (XmlSchemaSequence).

5. (XmlSchemaSequence) in turn contains that actually represent parameters associated.

6.ParameterAndType is the dictionary. Here key represents parameter name and value represents type of the parameter.

   public Dictionary<string, string> parseMessageAndReturnParameters(Message msg)
        {
            Dictionary<string, string> ParameterAndType = new Dictionary<string, string>();
            foreach (MessagePart msgpart in msg.Parts)
            {

                XmlQualifiedName typName = msgpart.Element;

                XmlSchemaElement lookup = (XmlSchemaElement)_schemas.Find(typName, typeof(XmlSchemaElement));

                XmlSchemaComplexType tt = (XmlSchemaComplexType)lookup.SchemaType;

                XmlSchemaSequence sequence = (XmlSchemaSequence)tt.Particle;
                int i=0;
                if (sequence != null)
                {
                    foreach (XmlSchemaElement childElement in sequence.Items)
                    {
                        ParameterAndType.Add(childElement.Name, childElement.SchemaTypeName.Name);
                        //Console.WriteLine("Element: {0} ,{1}", childElement.Name,childElement.SchemaTypeName.Name);
                    }
                }
            }

            return ParameterAndType;
        }

Complete Code

Here i am having the complete code that parses a wsdl document. Main() method is the entry point.

The List present inside the main method contains all the information related to the web service. Like the name of the service, method name, parameters and return types.

Each OperationInputOutputParams object inside the list represents a single web service method and parameters associated with that.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Web.Services.Description;
using System.Xml.Serialization;
using System.Xml.Schema;

namespace WSDLParser
{
    class Program
    {
        ServiceDescription serviceDescription = null;
        BindingCollection bindColl;
        PortTypeCollection portTypColl;
        MessageCollection msgColl;
        Types typs;
        XmlSchemas _schemas;
        public static void Main(string[] args)
        {
            Program p = new Program();
          List<OperationInputOutputParams> l=  p.returnOperationsParameters();
        }

        public Program()
        {
            XmlReader reader = new XmlTextReader(@"http://localhost:1525/WebService1.asmx?wsdl");


             serviceDescription = ServiceDescription.Read(reader);

             bindColl = serviceDescription.Bindings;

             portTypColl = serviceDescription.PortTypes;

             msgColl = serviceDescription.Messages;

             typs = serviceDescription.Types;

             _schemas = typs.Schemas;
        }

        public List<OperationInputOutputParams> returnOperationsParameters()
        {
            List<OperationInputOutputParams> lst = new List<OperationInputOutputParams>();

            foreach (Service ser in serviceDescription.Services)
            {
                String webServiceNmae = ser.Name.ToString();
                foreach (Port port in ser.Ports)
                {
                    string portName = port.Name;
                    string binding = port.Binding.Name;

                    Binding bind = bindColl[binding];

                    PortType portTyp = portTypColl[bind.Type.Name];


                    foreach (Operation op in portTyp.Operations)
                    {
                        
                        OperationMessageCollection opMsgColl = op.Messages;
                        OperationInput opInput = opMsgColl.Input;
                        OperationOutput opOutput = opMsgColl.Output;
                        string inputMsg = opInput.Message.Name;
                        string outputMsg = opOutput.Message.Name;

                        
                        Message msgInput = msgColl[inputMsg];
                       Dictionary<string, string> InputParam= parseMessageAndReturnParameters(msgInput);

                        Message msgOutput = msgColl[outputMsg];
                        Dictionary<string, string> OutputParams = parseMessageAndReturnParameters(msgOutput);

                        string operationName = op.Name;
                        OperationInputOutputParams operObj = new OperationInputOutputParams();
                        operObj.ClassName = webServiceNmae;
                        operObj.MethodName = operationName;
                        operObj.Parameters = InputParam;
                        operObj.ReturnType=OutputParams.Values.ToArray<string>()[0];
                        lst.Add(operObj);
                    }

                }

            }
            return lst;
        }

        public Dictionary<string, string> parseMessageAndReturnParameters(Message msg)
        {
            Dictionary<string, string> ParameterAndType = new Dictionary<string, string>();
            foreach (MessagePart msgpart in msg.Parts)
            {

                XmlQualifiedName typName = msgpart.Element;

                XmlSchemaElement lookup = (XmlSchemaElement)_schemas.Find(typName, typeof(XmlSchemaElement));

                XmlSchemaComplexType tt = (XmlSchemaComplexType)lookup.SchemaType;

                XmlSchemaSequence sequence = (XmlSchemaSequence)tt.Particle;
                int i=0;
                if (sequence != null)
                {
                    foreach (XmlSchemaElement childElement in sequence.Items)
                    {
                        ParameterAndType.Add(childElement.Name, childElement.SchemaTypeName.Name);
                        //Console.WriteLine("Element: {0} ,{1}", childElement.Name,childElement.SchemaTypeName.Name);
                    }
                }
            }

            return ParameterAndType;
        }
    }

    class OperationInputOutputParams
    {
        public string ClassName { set; get; }
        public string MethodName { set; get; }
        public string ReturnType { set; get; }
        public Dictionary<string, string> Parameters { set; get; }
    }
}

About these ads

Written by pavanarya

August 8, 2012 at 9:42 pm

Posted in CodeDom, WebServices

4 Responses

Subscribe to comments with RSS.

  1. hey great job

    Gladio Gent

    August 12, 2012 at 4:28 am

  2. good dude..

    Rahul

    September 28, 2013 at 2:59 pm

  3. nice post

    vikram

    March 20, 2014 at 3:46 pm


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 69 other followers

%d bloggers like this: