9

I have two classes, WebServiceRequest and OrderRequest. Each class has properties. OrderRequest inherits from WebServiceRequest - like so:

    public class WebServiceRequest
    {
        private string mAuthenticationToken;

        public string AuthenticationToken
        {
            get { return mAuthenticationToken; }
            set { mAuthenticationToken = value; }
        }
        ...
}

public class OrderRequest : WebServiceRequest
{

    private string mVendorId;
    public string VendorId
    {
        get { return mVendorId; }
        set { mVendorId = value; }
    }
    ...
}

OrderRequest is exposed via a WebMethod. When viewing the WSDL of the ASMX file that exposes OrderRequest (i.e. MyWebService.asmx?WSDL), both properties are visible - as they should be. However, when you view the SOAP Sample for the Web Method that exposes OrderRequest, only the VendorId property is visible, and not the inherited AuthenticationToken property. What's the deal?

Note: I've posted this issue as a bug on MS Connect: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=520200

Grinn
  • 5,370
  • 38
  • 51

3 Answers3

4

I managed to stumble back-asswords into the solution for my problem, even after Microsoft confirmed it as a bug (https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=520200) and I had given up and marked John's answer as accepted. Here's the solution:

http://code.msdn.microsoft.com/WsdlHelpGenerator/Release/ProjectReleases.aspx?ReleaseId=412

Go there, download the file, then add the following line under the system.web section of your Web.config file:

<webServices>
 <wsdlHelpGenerator href="CustomWsdlHelpGenerator.aspx"/>
</webServices>

The href property should point to the relative location of your file within your project. Thanks for your help John.

Grinn
  • 5,370
  • 38
  • 51
  • Glad to help, and thanks for posting the solution. This is the kind of thing we'll have to do on our own, now that ASMX web services are in maintenance mode (according to that Connect bug). – John Saunders Jan 13 '10 at 02:09
  • I know this question is years old, but this is no longer available ... does anyone have a copy? – Ross Presser Jul 14 '14 at 18:51
  • @RossPresser Perhaps this will be of service: http://blog.codinghorror.com/custom-wsdlhelpgenerator-webroot-error/ . If not, I found it by Googling, "CustomWsdlHelpGenerator.aspx". Perhaps you can find an answer by doing the same. – Grinn Jul 22 '14 at 21:32
2

It should not be necessary to use [XmlInclude].

You seem to be judging this to be a problem because of the appearance of the help page (what you get in the browser when you hit the .asmx URL). Don't do that. Instead, look to see what is actually returned.


Update: The OP created a Connect bug for this issue. This bug was resolved as "won't fix" on 1/11/2010:

We have confirmed that the inherited properties do not show up in SOAP Sample on the browser and that is indeed a bug in the product.

At this point, this area is in maintainance mode, and no active work is planned.

Community
  • 1
  • 1
John Saunders
  • 160,644
  • 26
  • 247
  • 397
  • 2
    Like I said, the WSDL and everything else is accurate - but the SOAP Samples (on the "help page") are not. This Web Service is consumed by our clients, and when I give them the asmx they look at it and are confused because it doesn't match our documentation. *I* know the samples aren't right, but it's not very professional looking for me to have to say, "by the way, ignore our samples on the asmx. It's a bug in .NET and we're not clever enough to figure out a way around it." – Grinn Dec 10 '09 at 14:27
  • I recommend you determine whether or not it's a bug, and which kind. I also recommend you recognize that ASMX web services are considered to be "legacy technology" by Microsoft, so if it's a bug, it won't be getting fixed. Note how WCF doesn't include a help page. – John Saunders Dec 10 '09 at 14:35
  • Good point. I should definitely expose the next version of this Web Service via WCF and just produce the SOAP Samples myself in my accompanying documentation. I'm not sure what you mean by, "whether or not it's a bug" though: The SOAP Sample doesn't expose all of the available properties, and if there is no way to cause it to expose them... what else would you call it? So, I guess the first step to determining if it's a bug is to see if there is a solution to the issue. Does anyone have any solutions out there? – Grinn Dec 10 '09 at 15:31
  • I mean, determine whether the base properties are sent and received. The samples are just a web page - they are not the service itself. See what the actual service actually does. – John Saunders Dec 10 '09 at 16:46
  • 1
    The service works fine. Those properties are sent and received. The issue is only visible in the samples. – Grinn Dec 10 '09 at 18:36
  • Then you should report the bug at http://connect.microsoft.com/visualstudio/ and post the URL to the Connect issue here (so readers can vote on the issue). Such a bug will not be fixed, in all likelihood, but go ahead and report it. – John Saunders Dec 10 '09 at 20:23
  • Thanks John. Here's the link: https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=520200 – Grinn Dec 14 '09 at 15:35
1

@Grinn's link is dead and googling CustomWsdlHelpGenerator.aspx didn't turn anything useful up. But I came across this:

Improving the ASP.NET Webservice Help Generator

It uses the approach @Grinn refers to and uses an XSL to transform the Wsdl data to reflect inheritance.

From the link:

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...

<webServices>
  <wsdlHelpGenerator href="WsdlHelpGenerator.aspx" />
</webServices>

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

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

protected override void OnPreLoad(EventArgs e) {
   base.OnPreLoad(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();
   xslt.Load(Server.MapPath("WsdlHelp.xsl"));

   foreach (ServiceDescription desc in descriptions)
   {
     // load original WSDL data
     MemoryStream ms1 = new MemoryStream(), ms2 = new MemoryStream();
     desc.Write(ms1);

     // 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;
     transformed.Add(ServiceDescription.Read(ms2));

     ms1.Dispose();
     ms2.Dispose();
   }
   descriptions = transformed;
}

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"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
        xmlns:s="http://www.w3.org/2001/XMLSchema">
  <xsl:output
    method="xml"
    indent="no"
    encoding="utf-8"
    omit-xml-declaration="no"
  />
  <!-- recursively dissolve any schema extension elements to the base structure -->

  <xsl:template match="/" xml:space="default">
    <xsl:apply-templates />
  </xsl:template>

  <xsl:template match="*" priority="0.5" xml:space="default">
    <xsl:copy>
      <xsl:copy-of select="attribute::*" />
      <xsl:choose>
        <xsl:when test="child::*" />
        <xsl:otherwise>
          <xsl:value-of select="." />
        </xsl:otherwise>
      </xsl:choose>
      <xsl:apply-templates select="child::*" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="s:complexType" priority="1.0">
    <xsl:element name="s:complexType" namespace="http://www.w3.org/2001/XMLSchema">
      <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:call-template>
        </xsl:if>
      </xsl:element>
    </xsl:element>
  </xsl:template>

  <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,':')" />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>
AceJordin
  • 442
  • 5
  • 13