Dynamic web service methods

B

blackhawk

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!
 
J

John Saunders [MVP]

blackhawk said:
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.
 
B

blackhawk

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

John Saunders [MVP]

blackhawk said:
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>
 
B

blackhawk

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

John Saunders [MVP]

blackhawk said:
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>.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top