/FancyWsdl

Overhauls the output of wsdl.exe

Primary LanguageC#

FancyWsdl

FancyWsdl post-processes C# proxy code for WSDL service definitions generated by tools such as wsdl.exe, svcutil.exe, or Visual Studio > Add Service Reference and introduces the following enhancements:

  • Make it possible to rename types and members
    Your tool-generated webservice code does not conform to the naming standards from the app in development? The service does not work anymore after renaming properties? FancyWsdl adds corresponding XML serialization attributes so you can rename types and members.
  • Apply C# naming conventions (PascalCase)
    Web service definitions (and the generated code) often doe not conform to the C# naming standards. FancyWsdl introduces Pascal casing for types and members.
  • Insert documentation (summary tags)
    How to generate .NET classes with comments from WSDL and XSD? There are some XSDs and WSDLs containing WSDL documentation (annotation), but tools such as wsdl.exe or svcutil.exe do not generate XML-comments from XSDs annotations? FancyWsdl allows you to turn those WSDL comments to XML comments in the generated proxy code.
  • Clean up code
    FancyWsdl introduces autoimplemented properties, adds using directives, and use attribute shortcuts.

Usage

  1. Generate C# proxy classes from WSDL file, e.g.
    • wsdl.exe https://example.com/ExampleService/?wsdl
    • svcutil.exe https://example.com/ExampleService/?wsdl
    • Visual Studio > Add Service Reference
  2. Run FancyWsdl on generated code,
    e.g. FancyWsdl.exe ExampleService.cs
    • 1st command line parameter: path to C# file with generated proxy classes

If your service definition has annotation/documentation elements, FancyWsdl can create appropriate summary tags in your C# code:

  1. Run FancyWsdl on generated code and pass service definition(s),
    e.g. FancyWsdl.exe ExampleService.cs https://example.com/ExampleService/?wsdl https://example.com/ExampleData.xsd
    • 1st command line parameter:
    • 2nd+ command line parameter(s): url to XSD or WSDL service definitions (containing documentation elements)

Sample output:

With FancyWsdl post-processing (after) Raw proxy code (before)
/// <summary> 
/// Bundles parcel information type data. 
/// </summary>
[GeneratedCode("wsdl", "4.8.3928.0")]
[Serializable]
[DebuggerStepThrough]
[DesignerCategory("code")]
[XmlType(Namespace = "http://dpd.com/common/service/types/ShipmentService")]
[XmlRoot("parcelInformationType")]
public partial class ParcelInformationType {

    /// <summary> 
    /// The parcel label number of the corresponding parcel. 
    /// </summary>
    [XmlElement("parcelLabelNumber", Form = XmlSchemaForm.Unqualified)]
    public string ParcelLabelNumber { get; set; }

    /// <summary> 
    /// The DPD reference for this parcel. 
    /// </summary>
    [XmlElement("dpdReference", Form = XmlSchemaForm.Unqualified)]
    public string DpdReference { get; set; }

    /// <summary> 
    /// The content for the parcel. 
    /// </summary>
    [XmlElement("output", Form = XmlSchemaForm.Unqualified)]
    public OutputType[] Output { get; set; }
}
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "4.8.3928.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://dpd.com/common/service/types/ShipmentService")]
public partial class parcelInformationType {

    private string parcelLabelNumberField;

    private string dpdReferenceField;

    private OutputType[] outputField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string parcelLabelNumber {
        get {
            return this.parcelLabelNumberField;
        }
        set {
            this.parcelLabelNumberField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public string dpdReference {
        get {
            return this.dpdReferenceField;
        }
        set {
            this.dpdReferenceField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("output", Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
    public OutputType[] output {
        get {
            return this.outputField;
        }
        set {
            this.outputField = value;
        }
    }
}

Enhancements

  • Property name in XmlElementAttribute (so it's possible to rename the property) & pascal-case property name

    Before:

    [XmlElement(...)]
    public string delisId { ... }

    After:

    [XmlElement("delisId", ...)]
    public string DelisId { ... }
  • Autoimplemented getters & setters

    Before:

    private string delisIdField;
    
    public string DelisId {
        get {
            return this.delisIdField;
        }
        set {
            this.delisIdField = value;
        }
    }

    After:

    public string DelisId { get; set; }
  • Nullable value types

    Before:

    [XmlElement(...)]
    public int DateFrom { get; set; }
    
    [XmlIgnore]
    public bool DateFromSpecified { get; set; }

    After:

    [XmlElement(...)]
    public int? DateFrom { get; set; }
    
    [XmlIgnore]
    public bool DateFromSpecified => this.DateFrom.HasValue;
  • Method name in SoapDocumentMethodAttribute (so it's possible to rename the method) & pascal-case method name

    Before:

    [SoapDocumentMethod(...)]
    public storeOrdersResponse storeOrders(...) {
        object[] results = this.Invoke("storeOrders", ...);
        return ...;
    }

    After:

    [SoapDocumentMethod(..., RequestElementName = "storeOrders", ResponseElementName = "storeOrdersResponse")]
    public storeOrdersResponse StoreOrders(...) {
        object[] results = this.Invoke(nameof(StoreOrders), ...);
        return ...;
    }
  • Enum values in XmlEnumAttribute (so it's possible to rename the enum value) & pascal-case enum value

    Before:

    public enum productAndServiceDataOrderType {
    
        consignment,
    
        [System.Xml.Serialization.XmlEnumAttribute("collection request order")]
        collectionrequestorder,
    
        /// <remarks/>
        [System.Xml.Serialization.XmlEnumAttribute("pickup information")]
        pickupinformation,
    }

    After:

    public enum productAndServiceDataOrderType {
    
        [XmlEnum("consignment")]
        Consignment,
    
        [XmlEnum("collection request order")]
        CollectionRequestOrder,
    
        [XmlEnum("pickup information")]
        PickupInformation,
    }
  • Type names in XmlRootAttribute (so it's possible to rename the type) & pascal-case type

    Before:

    public partial class parcelInformationType { ...
    }

    After:

    [XmlRoot("parcelInformationType")]
    public partial class ParcelInformationType { ...
    }
  • Documentation from XML schema

    Before:

    /// <remarks/>
    public partial class ParcelInformationType {
    
        /// <remarks/>
        public string ParcelLabelNumber { get; set; }
    
        /// <remarks/>
        public string DpdReference { get; set; }
    
        /// <remarks/>
        public OutputType[] Output { get; set; }
    }
    <schema ...>
        <xs:complexType name="parcelInformationType">
            <xs:annotation>
                <xs:documentation>Bundles parcel information type data.</xs:documentation>
            </xs:annotation>
            <xs:sequence>
                <xs:element maxOccurs="1" minOccurs="0" name="parcelLabelNumber" type="xs:string">
                    <xs:annotation>
                        <xs:documentation>The parcel label number of the corresponding parcel.</xs:documentation>
                    </xs:annotation>
                </xs:element>
                <xs:element maxOccurs="1" minOccurs="0" name="dpdReference" type="xs:string">
                    <xs:annotation>
                        <xs:documentation>The DPD reference for this parcel.</xs:documentation>
                    </xs:annotation>
                </xs:element>
                <xs:element maxOccurs="unbounded" minOccurs="0" name="output" type="tns:OutputType">
                    <xs:annotation>
                        <xs:documentation>The content for the parcel.</xs:documentation>
                    </xs:annotation>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </schema>

    After:

    /// <summary> Bundles parcel information type data. </summary>
    public partial class ParcelInformationType {
    
        /// <summary> The parcel label number of the corresponding parcel. </summary>
        public string ParcelLabelNumber { get; set; }
    
        /// <summary> The DPD reference for this parcel. </summary>
        public string DpdReference { get; set; }
    
        /// <summary> The content for the parcel. </summary>
        public OutputType[] Output { get; set; }
    }
  • Use usings & attribute shortcuts

    Before:

    using System;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Web.Services;
    using System.Web.Services.Protocols;
    using System.Xml.Serialization;
    
    [System.CodeDom.Compiler.GeneratedCodeAttribute("wsdl", "4.8.3928.0")]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Web.Services.WebServiceBindingAttribute(Name="ShipmentService_SOAP")]
    [System.Xml.Serialization.XmlRootAttribute("ShipmentService")]
    public partial class ShipmentServicePublic : System.Web.Services.Protocols.SoapHttpClientProtocol { ...
    }

    After:

    using System;
    using System.CodeDom.Compiler;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Threading;
    using System.Web.Services;
    using System.Web.Services.Description;
    using System.Web.Services.Protocols;
    using System.Xml.Schema;
    using System.Xml.Serialization;
    
    [GeneratedCode("wsdl", "4.8.3928.0")]
    [DebuggerStepThrough]
    [DesignerCategory("code")]
    [WebServiceBinding(Name="ShipmentService_SOAP")]
    [XmlRoot("ShipmentService")]
    public partial class ShipmentServicePublic_4_3 : SoapHttpClientProtocol { ...
    }