Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inherited properties do not appear in soap sample on asmx file

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

like image 270
Grinn Avatar asked Dec 09 '09 17:12

Grinn


3 Answers

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.

like image 181
Grinn Avatar answered Oct 20 '22 12:10

Grinn


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.

like image 31
John Saunders Avatar answered Oct 20 '22 12:10

John Saunders


@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>
like image 42
AceJordin Avatar answered Oct 20 '22 12:10

AceJordin