Click here to Skip to main content
15,745,335 members
Articles / Web Development / ASP.NET
Posted 17 Aug 2008


16 bookmarked

Improving the ASP.NET Webservice Help Generator to Reflect Inheritance

Rate me:
Please Sign up or sign in to vote.
3.63/5 (5 votes)
17 Aug 2008CPOL2 min read
Apply an XSL transformation to the service description of an ASP.NET webservice to generate better interface documentation.


XML webservices can be developed very easily within the .NET Framework, and moreover it provides us with a nice help generator so you can automatically show your clients how they have to talk with your service.

Unfortunately, the generated help doesn't reflect inherited data structures, so it becomes quite useless as soon as such structures are being used to build the interface. Inheritance is of course a very useful technique when authoring XML webservices. So, for instance, you may require login data for each request or you may want to reply some status data with each response. Thus every request structure may inherit a generic one and every response may inherit a generic response structure.


Data exchange between an XML webservice and its consumers is defined by a WSDL contract. The .NET Framework creates it automatically from the structures defined by the webservice author. Such a contract is represented externally by an XML Schema document and internally by an instance of the System.Web.Services.Description.ServiceDescription class. In either case, the WSDL reflects exactly any inheritance structure using the XML Schema extension element pointing to the base structure. However, the default help rendering algorithm doesn't follow these extension references, therefore base structures remain unseen.


You can write your own help generator in order to generate any kind of documentation pages you like. The location of the WsdlHelpGenerator can be defined in the web.config.

But I really don't want to rewrite or change the default rendering algorithm, so my solution is to modify the WSDL data slightly for it, using a simple XSL transformation that replaces any extension reference by the appropriate base structure. This can be done by handling the PreLoad event of the WsdlHelpGenerator, so no code needs to be changed at all, apart from adding two methods to the WsdlHelpGenerator class.

Three Steps to Solve the Problem

  1. Get the installed default description generator DefaultWsdlHelpGenerator.aspx (on my computer, it's in C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG) and save it as WsdlHelpGenerator.aspx in the web directory of your webservice. Open your web.config and put...

      <wsdlHelpGenerator href="WsdlHelpGenerator.aspx" />

    ... inside the <system.web> section.

  2. Open WsdlHelpGenerator.aspx and add these two methods directly below the Page_Load method:

    protected override void OnPreLoad(EventArgs e) {
       // transform any service description stored within HttpContext
       // cf. Page_Load: try "wsdlsWithPost" first and fall back to "wsdls"
       string key = Context.Items["wsdlsWithPost"] != null ?
                   "wsdlsWithPost" : "wsdls";
       serviceDescriptions = (ServiceDescriptionCollection)Context.Items[key];
       TransformServiceDescriptions(ref serviceDescriptions);
       Context.Items[key] = serviceDescriptions;
    void TransformServiceDescriptions(ref ServiceDescriptionCollection descriptions) {
       // modify each description by an XSLT processor
       ServiceDescriptionCollection transformed = new ServiceDescriptionCollection();
       System.Xml.Xsl.XslCompiledTransform xslt =
           new System.Xml.Xsl.XslCompiledTransform();
       foreach (ServiceDescription desc in descriptions)
         // load original WSDL data
         MemoryStream ms1 = new MemoryStream(), ms2 = new MemoryStream();
         // process WSDL data using WsdlHelp.xsl
         ms1.Position = 0;
         xslt.Transform(new System.Xml.XPath.XPathDocument(ms1), null, ms2);
         // replace current WSDL data with the transformed stream
         ms2.Position = 0;
       descriptions = transformed;
  3. Finally, to get this code working, put the transformation file WsdlHelp.xsl into the web directory of your webservice. It may look as follows:

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0"
      <!-- recursively dissolve any schema extension elements to the base structure -->
      <xsl:template match="/" xml:space="default">
        <xsl:apply-templates />
      <xsl:template match="*" priority="0.5" xml:space="default">
          <xsl:copy-of select="attribute::*" />
            <xsl:when test="child::*" />
              <xsl:value-of select="." />
          <xsl:apply-templates select="child::*" />
      <xsl:template match="s:complexType" priority="1.0">
        <xsl:element name="s:complexType" namespace="">
          <xsl:copy-of select="attribute::*" />
          <xsl:element name="s:sequence">
            <xsl:copy-of select=".//s:sequence/*" />
            <xsl:if test="./s:complexContent/s:extension">
              <xsl:comment> schema extension expanded: <xsl:value-of
                select="./s:complexContent/s:extension/@base"/> </xsl:comment>
              <xsl:call-template name="fetch-sequence">
                <xsl:with-param name="typename"
                  select="substring-after(./s:complexContent/s:extension/@base,':')" />
      <xsl:template name="fetch-sequence">
        <xsl:param name="typename" />
        <xsl:copy-of select="//s:complexType[@name = $typename]//s:sequence/*" />
        <xsl:if test="//s:complexType[@name = $typename]/s:complexContent/s:extension">
          <xsl:call-template name="fetch-sequence">
            <xsl:with-param name="typename"
              select="substring-after(//s:complexType[@name = $typename]
    				/s:complexContent/s:extension/@base,':')" />

Points of Interest

Once you have your own WsdlHelpGenerator, you can also easily modify the appearance, add your own stylesheets, your company logo, etc.

If you don't want to have your webservice method list sorted alphabetically, replace the SortedList methodsTable within the Page_Load method of the WsdlHelpGenerator by an unsorted list.

You may also have a look at the excellent article Externalizing Web Service Documentation and apply XSL transformation there. Just put the C# code above into the ServiceDescriptionGenerator.aspx.cs file.


  • 17th August, 2008: Initial post


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Written By
Software Developer
Germany Germany
I studied math and computer science in Berlin, focused on Algebraic Geometry. Experience in software development since 1999. I'm doing .NET during the day, but things like Perl and other stuff at night Wink | ;)

Comments and Discussions

QuestionWsdlHelpGenerator Pin
Harshada J.5-Jul-17 21:49
Harshada J.5-Jul-17 21:49 
QuestionWsdlHelpGenerator file Pin
Harshada J.5-Jul-17 21:21
Harshada J.5-Jul-17 21:21 
Hi have added WsdlHelpGenerator.aspx page to my web directory. I have added section in web.config file.
But this fle don't have any code behind page. '.cs' page.
So where to write two methods you have mentioned in your article
AnswerRe: WsdlHelpGenerator file Pin
Harshada J.5-Jul-17 21:28
Harshada J.5-Jul-17 21:28 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.