Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Reverse Engineering Through WSDL.EXE

18 Jan 2006 1  
WSDL.EXE is a .NET tool used to generate a client proxy or a server stub from a given WSDL.This tool is mainly useful for reverse engineering, for a given WSDL, or for a given .NET language.

Introduction

A Web Service interface can be used by multiple service providers to offer the same service but with different implementation and access points. If you have a WSDL document file path or URL, you can reverse engineer it to create a dummy Web Service component, then define your own implementation, or keep the Web Service component in a library for future use. If you don�t know where to find an interesting WSDL, you can use the UDDI browser to search WSDL in a UDDI registry.

Uses of WSDL.EXE

  1. It can be used to generate server stubs. If a programmer needs to upgrade a web service using Microsoft .NET when the existing web service is in VB 6.0 or any similar language, this up-gradation should not affect the existing client of this web service, i.e. the WSDL generated by the new application should remain the same. By using WSDL.EXE, we can produce server stubs for different languages like C#, VB.NET and C++.NET.
  2. It can be used to generate the client proxy.
  3. If you are developing client applications for a web service and if you don�t have access to the target web service, or the target is under development, then for testing purposes, you can create a dummy web service of the target web service from the WSDL file.
  4. It can be used to invoke XML web services dynamically. Did you ever think about invoking your XML Web Services dynamically without having to generate a client side proxy class at design/compile time with wsdl.exe or Visual Studio .NET? No need to know the exact Web Service description and endpoint at compile/design time. Just get your WSDL from UDDI (or from wherever you want, e.g. XMethods), specify the type to instantiate and the methods to call ... voila! Can be used from any .NET application or even an unmanaged resource.
  5. We can manually write the stub code by seeing the WSDL file, but this may generate a different WSDL if we don't follow the proper procedure, and especially if parameters for web methods contain complex data types then building a class for such complex data types just by seeing the WSDL file is very difficult, and if the WSDL generated by this new code is not the same as the WSDL generated by the old code then the existing clients may not be able to access this web service.

Using the tool

Let's assume that, what is shown below is the WSDL generated by any of your old application (VB 6.0):

<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions 
 xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
 xmlns:s="http://www.w3.org/2001/XMLSchema" 
 xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
 xmlns:tns="http://tempuri.org/" 
 xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" 
 xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" 
 targetNamespace="http://tempuri.org/" 
 xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
  <wsdl:types>
    <s:schema elementFormDefault="qualified" 
             targetNamespace="http://tempuri.org/">
      <s:element name="GetDetails">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" 
                    maxOccurs="1" ref="EmpType" />
          </s:sequence>
        </s:complexType>
      </s:element>
      <s:element name="GetDetailsResponse">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" 
                 name="GetDetailsResult" type="s:string" />
          </s:sequence>
        </s:complexType>
      </s:element>
    </s:schema>
    <s:schema elementFormDefault="qualified">
      <s:element name="EmpType" type="EmployeeType" />
      <s:complexType name="EmployeeType">
        <s:sequence>
          <s:element minOccurs="1" maxOccurs="1" 
            form="unqualified" name="EmployeerID" 
            type="s:int" />
          <s:element minOccurs="0" maxOccurs="1" 
            form="unqualified" name="Name" 
            type="NameType" />
          <s:element minOccurs="0" maxOccurs="1" 
            form="unqualified" name="SSN" 
            type="s:string" />
          <s:element minOccurs="0" maxOccurs="1" 
            form="unqualified" name="CurrentAddress" 
            type="AddressType" />
          <s:element minOccurs="0" maxOccurs="unbounded" 
            form="unqualified" name="PreviousAddress" 
            type="AddressType" />
          <s:element minOccurs="0" maxOccurs="1" 
            form="unqualified" name="DriverLicense" 
            type="s:string" />
          <s:element minOccurs="0" maxOccurs="unbounded" 
            form="unqualified" name="Phone" 
            type="PhoneType" />
          <s:element minOccurs="0" maxOccurs="1" 
            form="unqualified" name="DOB" type="s:string" />
          <s:element minOccurs="0" maxOccurs="1" 
            form="unqualified" name="YOB" type="s:string" />
        </s:sequence>
      </s:complexType>
      <s:complexType name="NameType">
        <s:sequence>
          <s:element minOccurs="0" maxOccurs="1" 
            form="unqualified" name="Surname" 
            type="s:string" />
          <s:element minOccurs="0" maxOccurs="1" 
            form="unqualified" name="First" 
            type="s:string" />
          <s:element minOccurs="0" maxOccurs="1" 
            form="unqualified" name="Middle" type="s:string" />
          <s:element minOccurs="0" maxOccurs="1" 
            form="unqualified" name="Gen" 
            type="s:string" />
        </s:sequence>
      </s:complexType>
      <s:complexType name="AddressType">
        <s:sequence>
          <s:element minOccurs="0" maxOccurs="1" 
            form="unqualified" name="StreetNumber" type="s:int" />
          <s:element minOccurs="0" maxOccurs="1" 
            form="unqualified" name="StreetName" type="s:string" />
          <s:element minOccurs="0" maxOccurs="1" 
            form="unqualified" name="City" type="s:string" />
          <s:element minOccurs="0" maxOccurs="1" 
            form="unqualified" name="State" type="s:string" />
          <s:element minOccurs="0" maxOccurs="1" 
            form="unqualified" name="Zip" type="s:string" />
        </s:sequence>
      </s:complexType>
      <s:complexType name="PhoneType">
        <s:sequence>
          <s:element minOccurs="0" maxOccurs="1" 
            form="unqualified" name="Type" type="s:string" />
          <s:element minOccurs="0" maxOccurs="1" 
            form="unqualified" name="Number" type="s:string" />
        </s:sequence>
      </s:complexType>
    </s:schema>
  </wsdl:types>
  <wsdl:message name="GetDetailsSoapIn">
    <wsdl:part name="parameters" element="tns:GetDetails" />
  </wsdl:message>
  <wsdl:message name="GetDetailsSoapOut">
    <wsdl:part name="parameters" element="tns:GetDetailsResponse" />
  </wsdl:message>
  <wsdl:portType name="EmpServiceSoap">
    <wsdl:operation name="GetDetails">
      <wsdl:input message="tns:GetDetailsSoapIn" />
      <wsdl:output message="tns:GetDetailsSoapOut" />
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="EmpServiceSoap" type="tns:EmpServiceSoap">
    <soap:binding 
      transport="http://schemas.xmlsoap.org/soap/http" 
      style="document" />
    <wsdl:operation name="AddEmployee">
      <soap:operation 
        soapAction="http://tempuri.org/GetDetails" 
        style="document" />
      <wsdl:input>
        <soap:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal" />
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="EmpService">
    <documentation xmlns="http://schemas.xmlsoap.org/wsdl/" />
    <wsdl:port name="EmpServiceSoap" binding="tns:EmpServiceSoap">
      <soap:address 
        location="http://localhost/Employee/EmpService.asmx" />
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

Now, I can develop the server stub from the above WSDL for any .NET language, using the following way:

////////////////syntax of wsdl.exe ////////////
>Wsdl.exe <url or path of wsdl file> /language: /server.

Here, the switch <url or path of wsdl file> specifies a URL or a path to a WSDL contract. /language: specifies the language to use for the generated proxy/stub class. Choose from 'CS', 'VB', 'JS', 'VJS'. The default is 'CS' (C#). Short form is '/l:'. /server: generates an abstract class for an XML web service implementation, using ASP.NET, based on the contracts. The default is to generate client proxy classes.

Procedure to create a web service from a given WSDL file

  1. Go to Visual Studio .NET 2003 command prompt.
  2. Type WSDL EmpService.wsdl /l:CS /server.

The output you will get will be as below:

Microsoft (R) Web Services Description Language 
Utility [Microsoft (R) .NET Framework, 
Version 1.1.4322.573] Copyright (C) Microsoft Corporation 1998-2002. 
All rights reserved. Writing file 
�C:\ProgramFiles\CommonFiles\System\MAPI\1033\nt\EmpService.cs� 

Now, if you open the "EmpService.cs" file, you will find the following code:

//----------------------------------------------

// <autogenerated>

//     This code was generated by a tool.

//     Runtime Version: 1.1.4322.2032

//

//     Changes to this file may cause incorrect

//     behavior and will be lost if

//     the code is regenerated.

// </autogenerated>

//----------------------------------------------


//

// This source code was auto-generated

// by wsdl, Version=1.1.4322.2032.

//

using System.Diagnostics;
using System.Xml.Serialization;
using System;
using System.Web.Services.Protocols;
using System.ComponentModel;
using System.Web.Services;


/// <remarks/>

[System.Web.Services.WebServiceBindingAttribute(Name= 
        "EmpServiceSoap", Namespace="http://tempuri.org/")]
public abstract class EmpService : 
                System.Web.Services.WebService
{
   
       /// <remarks/>

    [System.Web.Services.WebMethodAttribute()]
    [System.Web.Services.Protocols.
      SoapDocumentMethodAttribute("http://tempuri.org/GetDetails",
    RequestNamespace="http://tempuri.org/", 
          ResponseNamespace="http://tempuri.org/",
    Use=System.Web.Services.Description.SoapBindingUse.Literal,
    ParameterStyle=
      System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
    public abstract string AddEmployee(
      [System.Xml.Serialization.XmlElementAttribute(Namespace="")] 
      EmployeeType EmpType);
}

/// <remarks/>

public class EmployeeType
{
   
    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute(
          Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public int EmployeerID;
   
    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute(
          Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public NameType Name;
   
    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute(
          Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string SSN;
   
    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute(
          Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public AddressType CurrentAddress;
   
    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute("PreviousAddress", 
          Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public AddressType[] PreviousAddress;
   
    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute(
          Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string DriverLicense;
   
    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute("Phone", 
          Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public PhoneType[] Phone;
   
    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute(
          Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string DOB;
   
    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute(
          Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string YOB;
}

/// <remarks/>

public class NameType
{
   
    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute(
          Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string Surname;
   
    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute(
          Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string First;
   
    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute(
          Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string Middle;
   
    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute(
          Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string Gen;
}

/// <remarks/>

public class PhoneType
{
   
    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute(
          Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string Type;
   
    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute(
          Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string Number;
}

/// <remarks/>

public class AddressType
{
   
    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute(
          Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public int StreetNumber;
   
    /// <remarks/>

    [System.Xml.Serialization.XmlIgnoreAttribute()]
    public bool StreetNumberSpecified;
   
    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute(
          Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string StreetName;
   
    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute(
          Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string City;
   
    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute(
          Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string State;
   
    /// <remarks/>

    [System.Xml.Serialization.XmlElementAttribute(
          Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string Zip;
}

If you look at the above class, it has classes for each complex type defined in the WSDL file. Now, you can add this file to your web service. You can find that the abstract keyword is preceded before 'class EmpService' and the method 'string AddEmployee(int a,int b);', in the above file.

Now, we can remove 'abstract' keyword and provide the implementation for the method.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here