Dynamic web service methods

Discussion in 'ASP .Net Web Services' started by blackhawk, Apr 2, 2008.

  1. blackhawk

    blackhawk Guest

    I have written a web service that will take parameters for constructing a
    query and then return the results of that query using untyped XML. The
    problem is, most web service clients expect the return data to be strongly
    typed, or it will not handle the binding properly. And the parameters
    passed will dictate the number and the datatype of columns returned.

    What I would like to do, then, is have an external configuration file that
    has a list of predefined values for creating the queries and then have web
    methods generated from this configuration file when the web service is
    instantiated.

    I cannot seem to find a way to dynamically generate WSDL. Does anyone
    have any code that will do this, or perhaps point me into a direction that I
    can work through this?

    Thanks!
     
    blackhawk, Apr 2, 2008
    #1
    1. Advertising

  2. "blackhawk" <> wrote in message
    news:...
    > I have written a web service that will take parameters for constructing a
    > query and then return the results of that query using untyped XML. The
    > problem is, most web service clients expect the return data to be strongly
    > typed, or it will not handle the binding properly. And the parameters
    > passed will dictate the number and the datatype of columns returned.
    >
    > What I would like to do, then, is have an external configuration file that
    > has a list of predefined values for creating the queries and then have web
    > methods generated from this configuration file when the web service is
    > instantiated.
    >
    > I cannot seem to find a way to dynamically generate WSDL. Does anyone
    > have any code that will do this, or perhaps point me into a direction that
    > I
    > can work through this?
    >
    > Thanks!
    >


    You can dynamically generate a WSDL by using the ServiceDescription class
    (see
    http://msdn2.microsoft.com/en-us/library/system.web.services.description.servicedescription.aspx).

    There are a number of things you might consider. One is using the ADO.NET
    Entity Framework to generate a conceptual and object model of the data you
    want to return. One thing it does for you it so emit classes decorated with
    the [DataContract] and [DataMember] attributes, so that they can be exposed
    through WCF. This also gives you a method of fairly rapidly adding new types
    of data. You can also teach it to call stored procedures to return the data.

    Another thing you can use (if you're using .NET 2.0 or above) is the new
    DataSet designer. It has a nice feature that, if you drag and drop a stored
    procedure onto the design surface, it attempts to determine the shape of the
    data returned by the stored procedure, and will generate a strongly-typed
    DataTable to correspond to the shape of that data. It does require that the
    stored procedure can be called with NULL supplied as parameters and still
    return an empty rowset of the correct shape. This will result in VS.NET
    generating the code to fetch the data, as well as the schema that can be
    used by your clients to understand what data will be returned.

    Be careful here. DataSets are specific to .NET and you will have to test to
    see how your clients react to them. Some clients may be able to understand
    them, based on the schema provided. Others may not. In no case will you have
    an actual DataSet on the client side, unless your client is .NET.
    --
    --------------------------------------------------------------------------------
    John Saunders | MVP – Windows Server System – Connected System Developer


    --
    --------------------------------------------------------------------------------
    John Saunders | MVP – Windows Server System – Connected System Developer
     
    John Saunders [MVP], Apr 2, 2008
    #2
    1. Advertising

  3. blackhawk

    blackhawk Guest

    John,

    I have been able to get behind the web service using IHttpHandler and
    construct most of the WSDL from the ServiceDescriptions, but I am stuck on
    several aspects:

    1) When I programmatically create a schema and then compile it (using a
    SchemaSet or just the Schema itself), it does not get included in generated
    WSDL. I don't get any errors, just nothing happens.

    2) Aside from that, now that I have augmented the WSDL and created a new
    operation, I am not sure how to properly intercept the method call and then
    return the appropriate soap response. I always get a message that the
    response could not be parsed.

    What I attempted to do was intercept the POST request and send back a soap
    response that looks like:

    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
    xmlns:tns="http://tempuri.org/" xmlns:s="http://www.w3.org/2001/XMLSchema"
    xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
    xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
    targetNamespace="http://tempuri.org/"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
    <soap:Body>
    <Result>
    <option>test</option>
    <value>test</value>
    </Result>
    </soap:Body>
    </soap:Envelope>


    And here is the WSDL that I generated

    <?xml version="1.0" encoding="utf-8"?>
    <wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
    xmlns:tns="http://tempuri.org/" xmlns:s="http://www.w3.org/2001/XMLSchema"
    xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
    xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
    targetNamespace="http://tempuri.org/"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
    <wsdl:types>
    <s:schema elementFormDefault="qualified"
    targetNamespace="http://tempuri.org/">
    <s:element name="SampleView">
    <s:complexType>
    <s:sequence>
    <s:element minOccurs="0" maxOccurs="1" name="option"
    type="s:string" />
    <s:element minOccurs="0" maxOccurs="1" name="value"
    type="s:string" />
    </s:sequence>
    </s:complexType>
    </s:element>
    <s:element name="SampleViewResponse">
    <s:complexType>
    <s:sequence>
    <s:element minOccurs="0" maxOccurs="1" name="SubsetResult"
    type="tns:Result" />
    </s:sequence>
    </s:complexType>
    </s:element>
    <s:complexType name="Result">
    <s:sequence>
    <s:element minOccurs="0" maxOccurs="1" name="option"
    type="s:string" />
    <s:element minOccurs="0" maxOccurs="1" name="value"
    type="s:string" />
    </s:sequence>
    </s:complexType>
    </s:schema>
    <s:schema attributeFormDefault="qualified"
    elementFormDefault="qualified" targetNamespace="http://tempuri.org/" />
    </wsdl:types>
    <wsdl:message name="SampleViewSoapIn">
    <wsdl:part name="parameter" element="tns:SampleView" />
    </wsdl:message>
    <wsdl:message name="SampleViewSoapOut">
    <wsdl:part name="parameter" element="tns:SampleViewResponse" />
    </wsdl:message>
    <wsdl:portType name="SampleWebServiceSoap">
    <wsdl:eek:peration name="SampleView">
    <wsdl:input message="SampleViewSoapIn" />
    <wsdl:eek:utput message="SampleViewSoapOut" />
    </wsdl:eek:peration>
    </wsdl:portType>
    <wsdl:portType name="SampleWebServiceSoap12" />
    <wsdl:binding name="SampleWebServiceSoap" type="tns:SampleWebServiceSoap">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
    <wsdl:eek:peration name="SampleView">
    <soap:eek:peration soapAction="http://tempuri.org/SampleView"
    style="document" />
    <wsdl:input>
    <soap:body use="literal" />
    </wsdl:input>
    <wsdl:eek:utput>
    <soap:body use="literal" />
    </wsdl:eek:utput>
    </wsdl:eek:peration>
    </wsdl:binding>
    <wsdl:binding name="SampleWebServiceSoap12"
    type="tns:SampleWebServiceSoap12">
    <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
    </wsdl:binding>
    <wsdl:service name="SampleWebService">
    <wsdl:port name="SampleWebServiceSoap"
    binding="tns:SampleWebServiceSoap">
    <soap:address location="http://localhost:3733/SampleWebService.asmx" />
    </wsdl:port>
    <wsdl:port name="SampleWebServiceSoap12"
    binding="tns:SampleWebServiceSoap12">
    <soap12:address
    location="http://localhost:3733/SampleWebService.asmx" />
    </wsdl:port>
    </wsdl:service>
    </wsdl:definitions>
     
    blackhawk, Apr 3, 2008
    #3
  4. "blackhawk" <> wrote in message
    news:...
    >
    > John,
    >
    > I have been able to get behind the web service using IHttpHandler and
    > construct most of the WSDL from the ServiceDescriptions, but I am stuck on
    > several aspects:
    >
    > 1) When I programmatically create a schema and then compile it (using a
    > SchemaSet or just the Schema itself), it does not get included in
    > generated
    > WSDL. I don't get any errors, just nothing happens.
    >
    > 2) Aside from that, now that I have augmented the WSDL and created a new
    > operation, I am not sure how to properly intercept the method call and
    > then
    > return the appropriate soap response. I always get a message that the
    > response could not be parsed.
    >
    > What I attempted to do was intercept the POST request and send back a soap
    > response that looks like:
    >
    > <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    > xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
    > xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
    > xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
    > xmlns:tns="http://tempuri.org/" xmlns:s="http://www.w3.org/2001/XMLSchema"
    > xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
    > xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
    > targetNamespace="http://tempuri.org/"
    > xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
    > <soap:Body>
    > <Result>
    > <option>test</option>
    > <value>test</value>
    > </Result>
    > </soap:Body>
    > </soap:Envelope>
    >
    >
    > And here is the WSDL that I generated
    >


    A quick read of your WSDL shows that the response should be more like this:

    <soap:Envelope>
    <soap:Body>
    <SampleViewResponse>
    <SubsetResult/>
    <SubsetResult/>
    </SampleViewResponse>
    </soap:Body>
    </soap:Envelope>

    --
    --------------------------------------------------------------------------------
    John Saunders | MVP – Windows Server System – Connected System Developer
     
    John Saunders [MVP], Apr 3, 2008
    #4
  5. blackhawk

    blackhawk Guest

    John,

    I realized that after I posted. Here are the WSDL and responses I am
    actually returning now.

    WSDL:

    <?xml version="1.0" encoding="utf-8"?>
    <wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
    xmlns:tns="http://tempuri.org/" xmlns:s="http://www.w3.org/2001/XMLSchema"
    xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
    xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
    targetNamespace="http://tempuri.org/"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
    <wsdl:types>
    <s:schema elementFormDefault="qualified"
    targetNamespace="http://tempuri.org/">
    <s:element name="SampleMethod">
    <s:complexType>
    <s:sequence>
    <s:element minOccurs="0" maxOccurs="1" name="option"
    type="s:string" />
    <s:element minOccurs="0" maxOccurs="1" name="value"
    type="s:string" />
    </s:sequence>
    </s:complexType>
    </s:element>
    <s:element name="SampleMethodResponse">
    <s:complexType>
    <s:sequence>
    <s:element minOccurs="0" maxOccurs="1" name="Results"
    type="tns:Result" />
    </s:sequence>
    </s:complexType>
    </s:element>
    <s:complexType name="Result">
    <s:sequence>
    <s:element minOccurs="0" maxOccurs="1" name="option"
    type="s:string" />
    <s:element minOccurs="0" maxOccurs="1" name="value"
    type="s:string" />
    </s:sequence>
    </s:complexType>
    </s:schema>
    <s:schema attributeFormDefault="qualified"
    elementFormDefault="qualified" targetNamespace="http://tempuri.org/" />
    </wsdl:types>
    <wsdl:message name="SampleMethodSoapIn">
    <wsdl:part name="parameter" element="tns:SampleMethod" />
    </wsdl:message>
    <wsdl:message name="SampleMethodSoapOut">
    <wsdl:part name="parameter" element="tns:SampleMethodResponse" />
    </wsdl:message>
    <wsdl:portType name="WebServiceSoap">
    <wsdl:eek:peration name="SampleMethod">
    <wsdl:input message="SampleMethodSoapIn" />
    <wsdl:eek:utput message="SampleMethodSoapOut" />
    </wsdl:eek:peration>
    </wsdl:portType>
    <wsdl:portType name="WebServiceSoap12" />
    <wsdl:binding name="WebServiceSoap" type="tns:WebServiceSoap">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
    <wsdl:eek:peration name="SampleMethod">
    <soap:eek:peration soapAction="http://tempuri.org/SampleMethod"
    style="document" />
    <wsdl:input>
    <soap:body use="literal" />
    </wsdl:input>
    <wsdl:eek:utput>
    <soap:body use="literal" />
    </wsdl:eek:utput>
    </wsdl:eek:peration>
    </wsdl:binding>
    <wsdl:binding name="WebServiceSoap12" type="tns:WebServiceSoap12">
    <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
    </wsdl:binding>
    <wsdl:service name="WebService">
    <wsdl:port name="WebServiceSoap" binding="tns:WebServiceSoap">
    <soap:address location="http://localhost:3733/WebService.asmx" />
    </wsdl:port>
    <wsdl:port name="WebServiceSoap12" binding="tns:WebServiceSoap12">
    <soap12:address location="http://localhost:3733/WebService.asmx" />
    </wsdl:port>
    </wsdl:service>
    </wsdl:definitions>


    Response:

    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:tns="http://tempuri.org/">
    <soap:Body>
    <SampleMethodResponse>
    <Result>
    <option>test</option>
    <value>test</value>
    </Result>
    </SampleMethodResponse>
    </soap:Body>
    </soap:Envelope>
     
    blackhawk, Apr 3, 2008
    #5
  6. "blackhawk" <> wrote in message
    news:...
    > John,
    >
    > I realized that after I posted. Here are the WSDL and responses I am
    > actually returning now.
    >
    > WSDL:
    >
    > <?xml version="1.0" encoding="utf-8"?>
    > <wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    > xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
    > xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
    > xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
    > xmlns:tns="http://tempuri.org/" xmlns:s="http://www.w3.org/2001/XMLSchema"
    > xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
    > xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
    > targetNamespace="http://tempuri.org/"
    > xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
    > <wsdl:types>
    > <s:schema elementFormDefault="qualified"
    > targetNamespace="http://tempuri.org/">
    > <s:element name="SampleMethod">
    > <s:complexType>
    > <s:sequence>
    > <s:element minOccurs="0" maxOccurs="1" name="option"
    > type="s:string" />
    > <s:element minOccurs="0" maxOccurs="1" name="value"
    > type="s:string" />
    > </s:sequence>
    > </s:complexType>
    > </s:element>
    > <s:element name="SampleMethodResponse">
    > <s:complexType>
    > <s:sequence>
    > <s:element minOccurs="0" maxOccurs="1" name="Results"
    > type="tns:Result" />
    > </s:sequence>
    > </s:complexType>
    > </s:element>


    ....

    > Response:
    >
    > <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    > xmlns:tns="http://tempuri.org/">
    > <soap:Body>
    > <SampleMethodResponse>
    > <Result>
    > <option>test</option>
    > <value>test</value>
    > </Result>
    > </SampleMethodResponse>
    > </soap:Body>
    > </soap:Envelope>
    >


    It's the element name that determines which tag you use in the document, not
    the name of the complex type. That means that you need <Results>, not
    <Result>.

    --
    --------------------------------------------------------------------------------
    John Saunders | MVP – Windows Server System – Connected System Developer
     
    John Saunders [MVP], Apr 3, 2008
    #6
  7. blackhawk

    blackhawk Guest

    Doh! Brain fade! I totally missed that. Let me see if that fixes it.

    "John Saunders [MVP]" wrote:

    >
    >
    > "blackhawk" <> wrote in message
    > news:...
    > > John,
    > >
    > > I realized that after I posted. Here are the WSDL and responses I am
    > > actually returning now.
    > >
    > > WSDL:
    > >
    > > <?xml version="1.0" encoding="utf-8"?>
    > > <wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    > > xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
    > > xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
    > > xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
    > > xmlns:tns="http://tempuri.org/" xmlns:s="http://www.w3.org/2001/XMLSchema"
    > > xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
    > > xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
    > > targetNamespace="http://tempuri.org/"
    > > xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
    > > <wsdl:types>
    > > <s:schema elementFormDefault="qualified"
    > > targetNamespace="http://tempuri.org/">
    > > <s:element name="SampleMethod">
    > > <s:complexType>
    > > <s:sequence>
    > > <s:element minOccurs="0" maxOccurs="1" name="option"
    > > type="s:string" />
    > > <s:element minOccurs="0" maxOccurs="1" name="value"
    > > type="s:string" />
    > > </s:sequence>
    > > </s:complexType>
    > > </s:element>
    > > <s:element name="SampleMethodResponse">
    > > <s:complexType>
    > > <s:sequence>
    > > <s:element minOccurs="0" maxOccurs="1" name="Results"
    > > type="tns:Result" />
    > > </s:sequence>
    > > </s:complexType>
    > > </s:element>

    >
    > ....
    >
    > > Response:
    > >
    > > <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    > > xmlns:tns="http://tempuri.org/">
    > > <soap:Body>
    > > <SampleMethodResponse>
    > > <Result>
    > > <option>test</option>
    > > <value>test</value>
    > > </Result>
    > > </SampleMethodResponse>
    > > </soap:Body>
    > > </soap:Envelope>
    > >

    >
    > It's the element name that determines which tag you use in the document, not
    > the name of the complex type. That means that you need <Results>, not
    > <Result>.
    >
    > --
    > --------------------------------------------------------------------------------
    > John Saunders | MVP – Windows Server System – Connected System Developer
    >
    >
    >
     
    blackhawk, Apr 7, 2008
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. hocho888
    Replies:
    1
    Views:
    662
  2. George Nevsky

    How to control order of web methods on web service test page?

    George Nevsky, May 4, 2004, in forum: ASP .Net Web Services
    Replies:
    1
    Views:
    195
    Jan Tielens
    May 4, 2004
  3. Peter Cook

    Web Service with disappearing Web Methods

    Peter Cook, Sep 12, 2005, in forum: ASP .Net Web Services
    Replies:
    0
    Views:
    111
    Peter Cook
    Sep 12, 2005
  4. Leo Violette
    Replies:
    0
    Views:
    1,075
    Leo Violette
    Apr 17, 2009
  5. Kenneth McDonald
    Replies:
    5
    Views:
    345
    Kenneth McDonald
    Sep 26, 2008
Loading...

Share This Page