Delphi 6 preemptive research - BizSnap / SOAP / WebService
- Pass custom type data via SOAP
In the previous example (see "Delphi 6 preemptive research - BizSnap / SOAP / WebService - one Hello World!") We see that remote object calls can be easily performed through SOAP, although that example The object is a Delphi class, but in fact, you only need to make a SOAP package for the object, you can call all kinds of objects including COM / CORBA / EJB (except for EJBs must be implemented in Java, COM / CORBA can be implemented with Delphi ). In that example, the data type used by the interface method is a standard type, but the actual application often encounters the case where the custom type is passed. At this time, the operation is slightly troublesome, and the details such as Li Wei are fun, possibly Infinite New Technology -Web Service "is shown in the example. Similarly, here is also an example to illustrate the method of passing the custom data type through the SOAP, this example is a more trouble-to-server example: server: 1.New | WebServices | SOAP Server Application, as shown below: This example is used Web App Debugger (see "Delphi 6 Preferred Research - Web App Development and Debug"), set its coclass name to WadsoapDemo2, as shown below: 2.SAVEAll, Unit2 named: svrwmmain, Unit1 does not change the name, Project1 named: Server 3.New | Data Module, save this unit as SVRDATAMOD; 4. Put two DBEXPRESS controls: SqlConnection1 and SqlDataSet1, as shown below: It is set to:
SqlConnection1ConnectionName: = iblocal; loginprompt: = false; params.values ['Database']: = '[...] / example / database / employee.gdb'; // above [...] is installed for your interbase path SQLDataSet1SQLConnection: = SQLConnection1; CommandText: = 'select FULL_NAME, PHONE_EXT from EMPLOYEE WHERE EMP_NO =: EMP_NO'; 5.New | unit, this unit is saved as SvrDataType, which reads as follows: unit SvrDataType;
Interface
Uses
InvoKeregistry;
Type
Tempinfo = Class (Tremotable)
Private
FNAME: STRING;
FPHONE: STRINE;
Published
Property Name: String Read FName Write FName
Property Phone: String Read fPhone Write fPhone;
END;
IMPLEMENTATION
INITIALIZATION
RemclassRegistry.registerXSClass (Tempinfo); Finalization
RemclassRegistry.unregisterXSClass (Tempinfo);
End.
Class: Tempinfo is defined in this unit, used to record employee information, including two domains of Name and Phone, all of which are string types. For data types that need to be passed to the client, must be derived from the Tremotable class, which can automatically handle the passage of type information. If you want to manually process custom data types, you must derive from the TremotableXS class, which is similar to Tremotable, but in this way, two conversion methods must be implemented: NativeToxs and Xstonative, see Delphi6 / Source / SOAP / XSbuiltins.Pas Realization of several classes in. It should be noted that two attributes are placed in published in Published. He must do this here, I have used them in public, causing the client unable to get the data type information of the server, and then found them must Playing in public in public, so although it is not a control here, these properties are not displayed in the Object Inspector, but still need to be placed in public. This may be because Publisd is more Publico more RTTI (Run Time Type Info, runtime information), and the remote data type is dependent on RTTI. Finally, register and reverse this class in the remote class registration information library. 6.New | Unit, save this unit as SVRSOAPINTF, as follows: Unit Svrsoapintf;
Interface
Uses
InvokeRegistry, SVRDATYPE;
Type
IsoApeMPloyee = Interface (Iinvokable)
['{31903B5A-96B3-43C2-A7B5-F67F6DB829E5}']
Function GetEmployee (AEMPNO: Integer): Tempinfo; StdCall;
END;
IMPLEMENTATION
INITIALIZATION
INVREGISTRY.REGISTERFACE (IsoApemployee);
End.
The SOAP interface is defined in this unit, which is not a big difference with the previous example, but this interface is implemented in a separate unit in this time. The only difference is that the method in this interface gets geteMployee returns a custom data type: Tempinfo. 7. Join the SOAP implementation class in the SVRWMMAIN unit, the complete unit content is as follows: Unit svrwmmain
Interface
Uses
Sysutils, classes, httpapp, wsdlpub, soappasinv, soaphttpasinv,
SOAPHTTPDISP, WebBrokersoAP;
Type
Twebmodule2 = Class (Twebmodule)
HTTPSOAPDISPATCHER1: THTTPSOAPDISPATCHER;
HTTPSOAPSCALINVOKER1: THTTPSOAPSCALINVOKER;
Wsdlhtmlpublish1: TWSDLHTMLP Bublish;
Private
{Private Declarations}
PUBLIC {public declarations}
END;
VAR
WebModule2: twebmodule2;
IMPLEMENTATION
Uses WebReq, InvokeRegistry, Svrdattype, Svrsoapintf, SvrdataMod;
{$ R * .dfm}
Type
TSoAPemPloyee = Class (TinvokableClass, IsoApeMployee)
Protected
Function GetEmployee (AEMPNO: Integer): Tempinfo; StdCall;
END;
{TSoAPEMPLOYEEE}
Function TSoApemployee.geTemPloyee (AEMPNO: Integer): Tempinfo; stdcall;
Begin
RESULT: = Tempinfo.create;
IF (Not Assigned (Datamodule2)) THEN
DataModule2: = TDATAModule2.create (nil);
Try
DataModule2.SqlConnection1.Open;
With datamodule2.sqldataset1 do
Begin
PARAMBYNAME ('EMP_NO') .asinteger: = AEMPNO;
Open;
IF (not eof) THEN
Begin
Result.name: = FieldByname ('full_name') .sstring;
Result.Phone: = FieldByName ('phone_ext') .sstring;
End
Else
Begin
Result.name: = '';
Result.Phone: = '';
END;
CLOSE;
END;
DataModule2.sqlConnection1.close;
Finally
DataModule2.free;
DataModule2: = NIL;
END;
END;
INITIALIZATION
WebRequestHandler.WebmoduleClass: = TWEBModule2;
Invregistry.registerInvokableClass (TSoApemployee);
End.
The implementation and implementation of the TSOAPEMPLOYEE of the interface here is similar to the previous example. GetEmployee is not complex: First, if you do not create an instance of DataModule2 (you need to remove DataModule2 from automatic creation in Project | Options); then connect to the database, query the employee of the designated employee number Information; finally returns this information. Note: This uses DBEXPRESS, some places are not only like BDE / ADO, if you can't use RecordCount, you can only use EOF to determine if there is a query result. 8. This completes all the programs, compiles and runs, then exits the registration of the Web App DEBUGER application. Start the web app debugger, then start the browser, enter: http: // localhost: 1024 / server.wadsoapdemo2 / wsdl / isoaPloyee to browse its WSDL content, including the necessary information of the custom type, but if The properties of the Tempinfo class in the front SVRDATYPE unit are not placed in the Published section, which will not see type information. Here is the Types tag part of this WSDL:
xs: sequence>
xs: complexType>
xs: schema>
xs: sequence>
xs: complexType>
xs: schema>
XMLns: n1 = "http://schemas.xmlsoap.org/wsdl/" /> xs: restriction> xs: complextence> xs: complexType> xs: schema> type> From the above WSDL, you can see that the server exports three "complex types" - ComplexType: Tempinfo, TWSDLSOAPPORT, TWIDESTRINGDYNARRAY, where the Tempinfo is the type of data we define, the other is Delphi internal definition Type, we will see them again when the client is imported in WSDL. Look at the implementation of the client: 1.New | Application Create a normal VCL application; 2.saveall, unit1 named clnmain, project1 named client; 3. Put HttPrio1, Edit1, Button1, Label1, Label2, etc. on Form1 Controls, as shown below: EDIT1's text set to 1, button1's CAPTION set to getEmployee, HTTPRIO1 URL property set to: http: // localhost: 1024 / server.wadsoapdemo2 / soap; 4.new | Web Services | Web Services Importer, similar to the former example, only imported URLs to: http: // localhost: 1024 / server.wadsoapdemo2 / wsdl / isoaPloyee; 5. If the server's WSDL is as described above, three units will be imported into three units. The TWSDLSOAPPORT, TEMPINFO, ISOAPEMPLOYEE, where IsoApeMPloyee is the SOAP interface unit we know. Tempinfo is the data type we defined at the server. TWSDLSOAPPORT is a data type inside the Delphi, we have seen in the server's WSDL It has been reached. Save all, saved TWSDLSOAPPORT as ClNSoApport, saved Tempinfo as CLNDATYPE, saved IsoApeMPloyee as ClNSoAPintf. Note that the two units in the CLNSOAPINTF unit must be changed to ClNSoApport and ClndataType accordingly. Since the contents of these three units do not need to be changed, as long as the server is correct, it is not necessary to understand the contents of the three units (especially the other CLNSOAPINTF and CLNDATYPE and the corresponding unit of the server), so it is not listed here. Their content. 6. Double click on button1 Enter the following code: Procedure TFORM2.BUTTON1CLICK (Sender: TOBJECT); VAR EI: Tempinfo; Begin EI: = (httprio1 as isoailemployee) .geTETEMPLOYEE (Strtell (Edit1.Text)); IF (Assigned (EI)) THEN Begin Label1.caption: = ei.name; Label2.caption: = ei.phone; END; END; 7. Compilation operation, enter "1" or other database in Edit1, no corresponding record, press Button1, Label1 and Label2 to display empty; enter "2" or other databases have recorded employees, Display the full name of the employee in Label1, showing the telephone number of this employee in Label2, as shown below: It is not so complicated to see this example. Raptor Jun.20-01, OCT.20, OCT.24