![]() ![]() ![]() ![]() ![]() ![]() |
This chapter describes how to enable interoperability between Oracle Data Service Integrator and ADO.NET client applications. With support for ADO.NET client applications, Microsoft Visual Basic and C# developers who are familiar with Microsoft’s disconnected data model can leverage Oracle Data Service Integrator data services as if they were ADO.NET Web services.
From the Microsoft ADO.NET developers’ perspective, support is transparent: you need do nothing extraordinary to invoke Oracle Data Service Integrator operations (functions and procedures)—all the work is done on the server-side. ADO.NET-client-application developers need only incorporate the Oracle Data Service Integrator-generated web service into their programming environments, as you would when creating any Web service client application.
Information about how Oracle Data Service Integrator achieves ADO.NET integration is provided in this chapter, along with the server-side operations required to enable it. The chapter includes the following sections:
Note: | The details of ADO.NET development are described on Microsoft’s MSDN Web site (http://msdn.microsoft.com). See this site for information about developing ADO.NET-enabled applications. |
Functionally similar to the service data object (SDO), ADO.NET (Active Data Object) is data-object technology for Microsoft ADO.NET client applications. ADO.NET provides a robust, hierarchical, data access component that enables client applications to work with data while disconnected from the data source. Developers creating data-centric client applications use C#, Visual Basic.NET, or other Microsoft .NET programming languages to instantiate local objects based on schema definitions.
These local objects, called DataSets, are used by the client application to add, change, or delete data before submitting it to the server. Thus, ADO.NET client applications sort, search, filter, store pending changes, and navigate through hierarchical data using DataSets, in much the same way as SDOs are used by Oracle Data Service Integrator client applications.
See “Role of the Mediator API and SDO” on page 2-13 for more information about working with SDOs in a Java client application. Developing client applications to use ADO.NET DataSets is roughly analogous to the process of working with SDOs.
Although functionally similar on the surface, as you might expect with two dissimilar platforms (Java and .NET), the ADO.NET and SDO data models are not inherently interoperable. To meet this need, Oracle Data Service Integrator provides ADO.NET-compliant DataSets so that ADO.NET client developers can leverage data services provided by the Oracle Data Service Integrator, just as they would any ADO.NET-specific data sources.
Enabling a Oracle Data Service Integrator data service to support ADO.NET involves the following steps:
ADO.NET is a set of libraries included in the Microsoft .NET Framework that help developers communicate from ADO.NET client applications to various data stores. The Microsoft ADO.NET libraries include classes for connecting to a data source, submitting queries, and processing results.
The DataSet also includes several features that bridge the gap between traditional data access and XML development. Developers can work with XML data through traditional data access interfaces.
Note: | Although ADO.NET supports both connected (direct) and disconnected models, only the disconnected model is supported in the Oracle Data Service Integrator. |
ADO.NET client applications are typically created using Microsoft Windows Forms, Web Forms, C#, or Visual Basic. Microsoft Windows Forms is a collection of classes used by client application developers to create graphical user interfaces for the Windows .NET managed environment.
Web Forms provides similar client application infrastructure for creating web-based client applications. Any of these client tools can be used by developers to create applications that leverage ADO.NET for data sources.
Once the WSDL URL is available, your client can invoke data service operations and you can invoke functions on the data service and manipulate the DataSet objects in your code as you normally would.
Note: | The process of generating the WSDL and server-side artifacts is described in Generating an Oracle Data Service Integrator Web Services Mapper. |
Oracle Data Service Integrator supports ADO.NET at the data object level. That is, the Oracle Data Service Integrator maps inbound ADO.NET DataSet objects to SDO DataObjects, and maps outbound SDOs to DataSets. The mapping is performed transparently on the server, and is bidirectional.
As shown in Figure 7-3, the ADO.NET typed DataSet is submitted to and returned by Oracle Data Service Integrator. At runtime, when a Microsoft .NET client application makes a SOAP invocation to the ADO.NET-enabled Web service, the Web service intercepts the object, converts the .NET Dataset to an SDO Data Object, and passes it to Data Services.
Mapping, transformation, and packaging processes are transparent to client application developers and data services developers. Only the items listed in Table 7-4 are exposed to data service developers.
Customer.ds |
||
Customer.xsd |
||
CustomerDataSet.xsd |
||
CustomerNET.ws |
The WSDL generated by Oracle Data Service Integrator from an ADO.NET-enabled web services map is specific for use by Microsoft ADO.NET clients. Exposing data services as Web services that are usable by Java clients is generally the same, although the actual steps (and the generated artifacts) are specific to Java.
The process of providing ADO.NET clients with access to data services is a server-side operation that is initially enabled in Eclipse and takes place in the context of an application and Workshop for WebLogic.
The instructions in this section assume that you have created a dataspace project and that you want to provide an ADO.NET client application with access to data services. (For information about designing and developing data services, see the Data Services Developer’s Guide.)
Enabling an Oracle Data Service Integrator application to support ADO.NET clients involves doing the following:
In some cases, of course, there will already be existing operations that you want to make available to an ADO.NET client.
You need to generate an Oracle Data Service Integrator Web Services Mapper that maps data service functions to Web Service operations.
To generate a Web Services Mapper, do the following:
You can then drag and drop data service files and functions from the Project Explorer into your mapper.
The system automatically generates a Web Services Description Language (WSDL) file that can be used by Web service clients to invoke operations on the ADO.NET-enabled Web service:
Note: | The building of RPC-style Web services on top of Oracle Data Service Integrator is not supported. For this reason RPC-style Web services built on cannot be created from ADO.NET clients utilizing Oracle Data Service Integrator. |
From your ADO.NET client application, specify the path to locate the WSDL. The example uses VisualStudio as a client application.
http:// host:port/dataspace project name/ folder/.../mapperfile.ws?WSDL
For example, the web services mapper file created in Workshop for WebLogic:
http://localhost:7001/NewProject/TestMapper.ws?WSDL
Once you have imported the WSDL you will be able to execute its data service operations assuming that the Oracle Data Service Integrator-enabled server is running and your application has sufficient access privileges.
Fundamentally, Microsoft’s ADO.NET DataSet is designed to provide data access to a data source that is—or appears very much like—a database table (columns and rows). Although, later adapted for consumption of Web services, ADO.NET imposes many design restrictions on the Web service data source schemas.
Due to these restrictions, Oracle Data Service Integrator XML types (also called schemas or XSD files) that work fine with data services may not be acceptable to ADO.NET's DataSet.
This section explains how you can prepare XML types for consumption by ADO.NET clients. It covers both read and update from the ADO.NET client side to the Oracle Data Service Integrator server, specifically explaining how to:
Note: | See the Data Services Developer’s Guide for detailed information related to creating and working with XML types. |
There are several approaches to adapting XML types for use with an ADO.NET DataSet:
Note: | Any ADO.NET-compatible data service XML types also can be used by non-ADO.NET clients. |
Note: | This approach may increase the likelihood of having to work with inverse functions and custom updates. |
The following guidelines are provided to help you develop ADO.NET DataSet-compatible XML types (schemas) by providing pattern requirements for various data service artifacts.
Requirements for supporting a complex type in an ADO.NET DataSet include:
Note: | The name of an element of simple type need not be unique, unless the occurrence of the element is unbounded. |
Since ADO.NET does not support true recurring references among complex types, the requirements noted in Requirements for Complex Types should be followed when simulating schema definitions utilizing such constructs as the following:
As an example, if an address complex type has been referred to by both Company and Department, there should be two element definitions, CompanyAddress and DepartmentAddress, each with an anonymous complex type.
The following code illustrates this example:
<xsd:schema targetNamespace="urn:company.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="Company">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Name" type="xsd:string"/>
<xsd:element name="CompanyAddress">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="City" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="Department">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Name" type="xsd:string"/>
<xsd:element name="DepartmentAddress">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="City" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Requirements for supporting simple types in an ADO.NET DataSet include the following:
Requirements for using target namespaces and namespace qualification include:
Further information regarding XML schemas can be found at the following site:
For RPC-style web services, results are return as qualified or unqualified based on the setting of the schema attribute:
elementFormDefault
In general, for web services, you can override the elementFormDefault
by setting the form attribute for any child element. However, these individual settings are ignored for RPC-style web services since only the global setting (qualified or unqualified) is taken into account.
<s:schema elementFormDefault="qualified"
targetNamespace="http://temp.openuri.org/SampleApp/CustomerOrder.xsd"
xmlns:s0="http://temp.openuri.org/SampleApp/CustomerOrder.xsd"
xmlns:s="http://www.w3.org/2001/XMLSchema">
<s:complexType name="ORDER">
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" form="unqualified"
name="ORDER_ID" type="s:string"/>
<s:element minOccurs="0" maxOccurs="1" form="unqualified"
name="CUSTOMER_ID" type="s:string"/>
</s:sequence>
</s:complexType>
</s:schema>
In this code sample, the global element is qualified but a child element (ORDER_ID
) is unqualified.
In the standard case, the special setting of unqualified for ORDER_ID
is honored. In the case of RPC-style web services, however, the runtime generates qualified attributes for all of the elements, including ORDER_ID
.
Note: | RPC-style web services such as those generated by ADO.NET may contain child elements with form attributes which do not match the schema’s elementFormDefault declaration. To turn these web services into executable data service operations, make sure that all form element attributes and the elementFormDefault attribute are in agreement (either qualified or unqualified). |
Multi-dimensional arrays in RPC mode are not supported.
The process of creating a ADO.NET-enabled Data Service and Web service generates two ADO.NET-specific artifacts:
Technical specifications for these artifacts are included in this section.
The Typed DataSet schema file is referred to in the dynamically-generated WSDL. The schema file is retrieved by the .NET client dynamically during web reference creation.
In the generated schema, the root element has the IsDataSet attribute (qualified with the Microsoft namespace alias, msdata) set to True, as in:
msdata:IsDataSet="true"
In keeping with Microsoft’s requirements for ADO.NET artifacts, the generated target schema of the data service and all schemas upon which it depends are contained in the same file as the schema of the typed DataSet. As you select functions to add to the control, WebLogic Workshop obtains the associated schemas and copies the content into the schema file.
In addition, the generated schema includes:
Listing 7-1 shows an excerpt of a schema—CustomerDS.xsd
—for a typed DataSet generated from an Oracle Data Service Integrator Customer schema.
<xs:schema xmlns:mstns="http://temp.openuri.org/schemas/Customer.xsd" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns="http://temp.openuri.org/schemas/Customer.xsd" targetNamespace="http://temp.openuri.org/schemas/Customer.xsd" id="CustomerDS" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element msdata:IsDataSet="true" name="CustomerDataSet">
<xs:complexType>
<xs:choice maxOccurs="unbounded">
<xs:element ref="CUSTOMER"/>
</xs:choice>
</xs:complexType>
</xs:element>
<xs:element name="CUSTOMER">
. . .
</xs:element>
</xs:schema>
The WSDL generated from the mapper file contains import statements that correspond to each typed DataSet. Each of the import statements is qualified with the namespace of its associated DataSet schema, as in the following example:
<import namespace="http://temp.openuri.org/schemas/Customer.xsd" location="LDTest1NET/CustomerDataSet.xsd"/>
In addition, the WSDL includes the ADO.NET compliant wrapper type definitions. The wrappers’ type definitions comprise complex types that contain sequences of any type element from the same namespace as the typed DataSet, as follows:
<s:complexType name="CustomerDataSetWrapper">
<s:sequence>
<s:any namespace="http://temp.openuri.org/schemas/Customer.xsd"/>
</s:sequence>
</s:complexType>
Below is a sample CUSTOMER_VIEW DataSet.xsd file:
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"
xmlns:tns="ld:logicalDS/CUSTOMER_VIEW"
targetNamespace="ld:logicalDS/CUSTOMER_VIEW"
id="CUSTOMER_VIEWDataSet" xmlns:xs="http://www,w3,org/2001/XMLSchema">
<xs:element msdata:IsDataSet="true"
name="CUSTOMER_VIEWDataSet">
<xs:complexType>
<xs:choice maxOccurs="unbounded">
<xs:element ref="tns:CUSTOMER_VIEW" />
<xs:choice>
<xs:complexType>
<xs:element>
<xs.element name="CUSTOMER_VIEW">
<xs:complexType>
<xs:sequence>
<xs:element name="CUSTOMER_ID" type="xs.string" />
<xs:element name="FIRST_NAME" type="xs.string" />
<xs:element name="LAST_NAME" type="xs.string" />
<xs:element name="CUSTOMER_SINCE" type="xs.dateTime" />
<xs:element name="EMAIL_ADDRESS" type="xs.string" />
<xs:element name="TELEPHONE_NUMBER" type="xs.string" />
<xs:element minOccurs="0"name="SSN" type="xs.string" />
<xs:element minOccurs="0"name="BIRTH_DAY" type="xs.dateTime" />
<xs:element minOccurs="0"name="DEFAULT_SHIP_METHOD"Type="xs.string"/>
<xs:element minOccurs="0"name="EMAIL_NOTIFICATION"Type="xs.integer"/>
<xs:element minOccurs="0"name="NEWS_LETTER"Type="xs.integer"/>
<xs:element minOccurs="0"name="ONLINE_STATEMENT"Type="xs.integer"/>
<xs:element minOccurs="0"name="CREDIT_LIMIT"Type="xs.decimal"/>
<xs:element name="ORDERS">
<xs.complexType>
<xs.sequence>
<xs.element minOccurs="0" maxOccurs="unbounded"name="ORDER">
<xs.complexType>
<xs.sequence>
<xs:element name="CUSTOMER_ID" type="xs.string" />
<xs:element name="ORDER_ID" type="xs.string" />
<xs:element name="ORDER_DATE" type="xs.dateTime" />
<xs:element name="SHIP_METHOD" type="xs.string" />
<xs:element name="HANDLING_CHARGE" type="xs.decimal" />
<xs:element name="SUBTOTAL" type="xs.decimal" />
<xs:element name="TOTAL_ORDER_AMOUNT" type="xs.decimal" />
<xs:element name="SUBTOTAL" type="xs.decimal" />
<xs:element name="SALE_TAX" type="xs.decimal" />
<xs:element name="SHIP_TO" type="xs.string" />
<xs:element name="SHIP_TO_NAME" type="xs.string" />
<xs:element name="BILL_TO" type="xs.string" />
<xs:element name="ESTIMATED_SHIP_DATE" type="xs.dateTime" />
<xs:element name="STATUS" type="xs.string" />
<xs:element minOccurs="0"name="TRACKING_NUMBER"type="xs.string"/>
<xs.sequence>
<xs.complexType>
<xs:element>
<xs.sequence>
<xs.complexType>
<xs:element>
<xs.sequence>
<xs.complexType>
</xs.schema>
Below is a sample CUSTOMER_VIEW_Net WSDL file:
<?xml version="1.0" encoding="utf-8"?>
<definitions xmlns:tns="ld"LogicalDSs/Customer_view_net.ws"
xmlns:soap= "http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="ld:LogicalDSs/Customer_view_net.ws"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<documentation>Oracle Data Service Integrator Web Service</documentation>
<import namespace="ld:logicalDS/CUSTOMER_VIEW" location=DSP_DOT_NET_SCHEMAS/LogicalDSs/schemas/CUSTOMER_VIEW
/CUSTOMER_VIEW DataSet.xsd/>
<types>
<xs:schema xmlns:stns="ld:logicalDS/customer_view_net.ws"
xmlns:dsns0="ld:logicalDS/CUSTOMER_VIEW"
elementFormDefault="qualified"
targetNamespace="ld:logicalDSs/customer_view_net.ws">
<xs:element name="getFirst">
<xs:complexType>
<xs:sequence/>
</xs:complexType>
</xs:element>
<xs:element name="getFirstResponse">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="getFirstResult"
type="stns:CUSTOMER_VIEWDataSetWrapper" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="createCUSTOMER_VIEW">
<xs:complexType>
<xs:sequence>
<XS:ELEMENT NAME="P">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded"
ref="dsns0:CUSTOMER_VIEW" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="createCUSTOMER_VIEWResponse">
<xs:complexType>
<xs:sequence />
</xs:complexType>
</xs:element>
<xs:element name="updateCUSTOMER_VIEW">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="p"
type="stns:CUSTOMER_VIEWDataSetWrapper" />
<xs:sequence>
<xs:complexType>
</xs:element>
<xs:element name="updateCUSTOMER_VIEWResponse">
<xs:complexType>
<xs:sequence />
</xs:complexType>
</xs:element>
<xs:element name="deleteCUSTOMER_VIEW">
<xs:complexType>
<xs:sequence>
<xs:element name="p">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded"
ref="dsns0:CUSTOMER_VIEW" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="deleteCUSTOMER_VIEWResponse">
<xs:complexType>
<xs:sequence />
</xs:complexType>
</xs:element>
<xs:element name="getAll">
<xs:complexType>
<xs:sequence />
</xs:complexType>
</xs:element>
<xs:element name="getAllResponse">
<xs:complexType>
<xs:sequence>
<xs.element minOccurs="0" name="getAllResult"
type="stns:CUSTOMER_VIEWDataSetWrapper">
<xs.sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="CUSTOMER_VIEWDataSetWrapper">
<xs:sequence>
<xs:any namespace="ld:logicalDS/CUSTOMER_VIEW" />
</xs:sequence>
</xs:complexType>
</xs.schema>
</types>
<message name="getAllIn">
<part name="parameters" element="tns:getAll" />
</message>
<message name="getAllOut">
<part name="parameters" element="tns:getAllResponse" />
</message>
<message name="getFirstIn">
<part name="parameters" element="tns:getFirst" />
</message>
<message name="getFirstOut">
<part name="parameters" element="tns:getFirstResponse" />
</message>
<message name="createCUSTOMER_VIEWIn">
<part name="parameters" element="tns:createCUSTOMER_VIEW" />
</message>
<message name="createCUSTOMER_VIEWOut">
<part name="parameters" element="tns:createCUSTOMER_VIEWResponse" />
</message>
<message name="updateCUSTOMER_VIEWIn">
<part name="parameters" element="tns:updateCUSTOMER_VIEW" />
</message>
<message name="updateCUSTOMER_VIEWOut">
<part name="parameters" element="tns:updateCUSTOMER_VIEWResponse" />
</message>
<message name="deleteCUSTOMER_VIEWIn">
<part name="parameters" element="tns:deleteCUSTOMER_VIEW" />
</message>
<message name="deleteCUSTOMER_VIEWOut">
<part name="parameters" element="tns:deleteCUSTOMER_VIEWResponse" />
</message>
<portType name="Customer_view_netPT">
<operation name="getAll">
<input message="tns:getAllIn" />
<output message="tns:getAllOut" />
</operation>
<operation name="getFirst">
<input message="tns:getFirstIn" />
<output message="tns:getFirstOut" />
</operaton>
<operation name="createCUSTOMER_VIEW">
<input message="tns:createCUSTOMER_VIEWIn" />
<output message="tns:createCUSTOMER_VIEWOut" />
</operaton>
<operation name="updateCUSTOMER_VIEW">
<input message="tns:updateCUSTOMER_VIEWIn" />
<output message="tns:updateCUSTOMER_VIEWOut" />
</operaton>
<operation name="deleteCUSTOMER_VIEW">
<input message="tns:deleteCUSTOMER_VIEWIn" />
<output message="tns:deleteCUSTOMER_VIEWOut" />
</operaton>
</portType>
<binding name+"Customer_view_netSoapBinding"
type="tns:Customer_view_netPT">
<soap:binding
transport="http://schemas.xmlsoap.org/soap/http" />
<operation name="getAll">
<soap:operation
soapAction="ld:LogicalDSs/Customer_view_net.ws/getAll"
style="document" />
<input>
<soap:body use="literal" />
</ input>
<output>
<soap:body use="literal" />
</output>
</operation>
<operation name="getFirst">
<soap:operation
soapAction="ld:LogicalDSs/Customer_view_net.ws/getFirst"
style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
<operation name="createCUSTOMER_VIEW">
<soap:operation
soapAction="ld:LogicalDSs/Customer_view_net.ws/createCUSTOMER_VIEW"
style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
<operation name="updateCUSTOMER_VIEW">
<soap:operation
soapAction="ld:LogicalDSs/Customer_view_net.ws/updateCUSTOMER_VIEW"
style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
<operation name="deleteCUSTOMER_VIEW">
<soap:operation
soapAction="ld:LogicalDSs/Customer_view_net.ws/deleteCUSTOMER_VIEW"
style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
</binding>
<service name="Customer_view_netSoapService">
<port name="Customer_view_netSoapPort"
binding="tns:Customer_view_netSoapBinding"
<soap:address
location="http://172.16.38.38:7001/RTLApp/ODSIWebService/LogicalDSds/
Customer_view_net.ws" />
</port>
</service>
</definitions>
![]() ![]() ![]() |