Morfik 07 - Creating and Using WebMethods
From Morfikwiki.com
Contents |
[edit] What are WebMethods?
WebMethods are a web version of the relational database’s stored procedures. They are routines or services which can be called when required by your application or be published so as to be called from other applications. WebMethods are implemented fully on the server, but have a Browser side component so as to allow easy usage from within the same XApp. It is through the creation of WebMethods that you build the Web Services interface of your XApp.
[edit] What is a Web Service?
Well, the World Wide Web Consortium (W3C) defines a Web Service as a software system designed to support interoperable machine-to-machine interaction over a network. Though this is a very broad definition, actual usage normally refers to SOAP (Simple Object Access Protocol) formatted XML envelopes for a transport and WSDL (Web Services Definition Language) files for the interface definition. This, more restrictive description, is the one accepted and backed by the Web Services Interoperability Organization (WS-I).
No other Web development tool allows you to create Web Services in so effortless a manner. Basically, you only need to worry about your business logic and leave the rest to the Morfik Framework.
[edit] How do WebMethods Work?
WebMethods are divided in two parts, a browser and a server part. In truth, a WebMethod’s logic can be mostly implemented on the browser side or on the server side. It is usual, however, for them to have a bit of code on both sides, with the bulk of the work being handled on the server. Also usually, the code on the browser side is mostly related to processing the reply sent by the server, i.e. doing something meaningful with return parameters from the WebMethod call.
[edit] Creating a WebMethod
As with all high level objects in Morfik, there are two ways you can create a new WebMethod in your application: by going through a wizard or directly to WebMethod design view. If you choose to go through the Wizard, it will ask you to specify what parameters will be passed on calling this WebMethod.
When you choose to create a WebMethod you will get a High Level object composed of two Common Object Classes, one for the browser and one for the server side of your application, just as with Forms. In order to implement your WebMethod all you have to do is write the code for two methods, one for each side of the application.
On the server side you will have the Execute method and on the browser side you will have the HandleResponse method. The way to have information channeled from one of these sides of the application to the other is to use the WebMethod Parameters.
[edit] WebMethod Parameters
WebMethod parameters are very much like function parameters. You specify the values for the parameters when you call the WebMethod and from that moment on, parameters values are known and kept updated whenever you can access them, be it on the browser or on the server side of your code. Note that changes to "in" parameters are not reflected back to the browser. When an "in" parameter is accessed from browser side code, its value will be the original value specified when the WebMethod was called.
It is also important to note that you do not need to specify any values for parameters that have default values.
In Figure 1 you can see the Editor for the WebMethod Parameters in Morfik.
You can also create the parameters though a Wizard, if you choose to create the WebMethod itself using the Create WebMethod Wizard. You can see in Figure 2, the Create WebMethod Wizard’s window along with a small window which is used for the developer to input information on each of the desired parameters.
The process of creating the WebMethod’s parameters is quite straightforward and should be quite simple to complete. In order to give you a quick look at how the WebMethods work I have created a small sample with the set of Parameters listed in Figure 1. This simple demo application uses a WebMethod to process simple mathematical operations on the server side of the application.
[edit] Server Side Code
As previously mentioned, usually the server side code of a WebMethod does most of its heavy work. In this case it is doing the actual math operations and preparing the result to be sent back to the browser side of the application.
In listing 1 you can see the code for the server side common object class that implements that half of the WebMethod high level object.
Listing 1 – Server side code of the MathProcessor WebMethod.
Unit MathProcessor;
Interface
Type
MathProcessor = Class(WebMethod)
Operand1 : Double;
Operand2 : Double;
theOperator : String;
theResult : Double;
Status : Integer;
Private
{ Private declarations }
Public
{ Public declarations }
Procedure Execute; override;
End; ['Published=False'];
Implementation
Procedure MathProcessor.Execute;
Begin
Status := 0;
if theOperator = 'ADD' then
theResult := Operand1 + Operand2
else
if theOperator = 'SUB' then
theResult := Operand1 - Operand2
else
if theOperator = 'DIV' then
theResult := Operand1 / Operand2
else
if theOperator = 'MUL' then
theResult := Operand1 * Operand2
else
Status := 1;
End;
End.
[edit] Browser Side Code
The Browser side of this WebMethod involves getting the result of the operation from the server and then doing something with it. Now, an interesting question is: what does the browser side of the WebMethod do with the results it just received from the server? Since the call to execute a WebMethod is asynchronous, as we will discuss shortly, there is nothing to return the results to. In this case the browser side HandleResponse method takes on the responsibility of displaying the results in a TextLabel control. You can see this code in Listing 2.
Listing 2 – Browser side code of the MathProcessor WebMethod.
Unit MathProcessor;
Interface
Type
MathProcessor = Class(WebMethod)
Operand1 : Double;
Operand2 : Double;
theOperator : String;
theResult : Double;
Status : Integer;
Private
{ Private declarations }
Public
{ Public declarations }
Procedure HandleResponse; override;
End;
Implementation
uses Index, SystemControls;
Procedure MathProcessor.HandleResponse;
Begin
Index(xApp.Forms['Index']).ResultLabel.Caption := FloatToStr(theResult);
End;
End.
In order to test this WebMethod I created a very small test application with a single form. You can see in Figure 3, this application at runtime within Internet Explorer.
[edit] Browser or Server Side?
WebMethods are a construct for running specific sets of commands on the server side of your application. The browser side of your code should just process the response it received from the server side, even though you can write code within the HandleResponse method to do other things, for example, you could achieve the same results we have with the WebMethod shown in listings 1 and 2 could be achieved, with all the logic on the Browser side, if we changed the browser side to be as is shown in listing 3. This practice, however, is not encouraged since it offers no benefit over the creation of an ordinary function, which will accomplish the same results. This kind of implementation will, also, be useless when you want to publish Web Services.
Listing 3 – WebMethod’s logic implemented in the Browser side.
Unit MathProcessor;
Interface
Type
MathProcessor = Class(WebMethod)
Operand1 : Double;
Operand2 : Double;
theOperator : String;
theResult : Double;
Status : Integer;
Private
{ Private declarations }
Public
{ Public declarations }
Procedure HandleResponse; override;
End;
Implementation
uses Index, SystemControls;
Procedure MathProcessor.HandleResponse;
Begin
if theOperator = 'ADD' then
theResult := Operand1 + Operand2
else
if theOperator = 'SUB' then
theResult := Operand1 - Operand2
else
if theOperator = 'DIV' then
theResult := Operand1 / Operand2
else
if theOperator = 'MUL' then
theResult := Operand1 * Operand2
else
Status := 1;
Index(xApp.Forms['Index']).ResultLabel.Caption := FloatToStr(theResult);
End;
End.
Notice that in this case, all the actual mathematical operations were transferred to the browser side, within the HandleResponse method.
[edit] Using a WebMethod
Up to this point we have seen how to create a new WebMethod and how to write some code for both its browser and server side parts, but how to we use this code? How do we invoke a WebMethod?
[edit] Invoking a WebMethod
In order to invoke a WebMethod you need to make a call to the RunWebMethod function, passing its name and the parameters which are required by the WebMethod. The parameters for the invoked WebMethod are passed as a single string, composed of a series of pairs in the following pattern:
parameter_name=parameter_value
These pairs are enclosed in double quotes and separated by commas. Whether the string itself is involved in single or double quotes depends on the string delimiters of the developer’s language syntax of choice.
In listing 4 you can see the source code for the simple test Form, which invokes the MathProcessor WebMethod on the click of a button.
Listing 4 – Invoking a WebMethod from an Object Pascal language Form.
Unit Index;
Interface
Type
Index = Class(Form)
OpTxt1 : TextEdit;
OpTxt2 : TextEdit;
OperatorCombo : ComboBox;
EqualsButton : Button;
PaintBox1 : PaintBox;
ResultLabel : TextLabel;
Procedure EqualsButtonClick(Event: TDOMEvent); Message;
Private
{ Private declarations }
Public
{ Public declarations }
End;
Implementation
Procedure Index.EqualsButtonClick(Event: TDOMEvent);
Begin
RunWebMethod('MathProcessor', '"Operand1=' + OpTxt1.Text +'",' +
'"Operand2=' + OpTxt2.Text +'",' +
'"theOperator=' + OperatorCombo.Text +'"');
End;
End.
For an example of how this WebMethod could be used in modules written in other language syntaxes, look at the code in listing 5. You can see the code necessary to invoke the same MathProcessor WebMethod from a Form in Morfik Basic syntax.
Listing 5 – Invoking a WebMethod from a Basic language Form.
Namespace Form1
Public Class Form1
Inherits Form
Published OpTxt1 As TextEdit
Published OpTxt2 As TextEdit
Published OperatorCombo As ComboBox
Published EqualsButton As Button
Published PaintBox1 As PaintBox
Published ResultLabel As TextLabel
Published Message Sub EqualsButtonClick(Event As TDOMEvent)
RunWebMethod("MathProcessor", """Operand1=" & OpTxt1.Text & """," & _
"""Operand2=" & OpTxt2.Text & """," & _
"""theOperator=" & OperatorCombo.Text _
& """")
End Sub
End Class
End Namespace
Due to Morfik’s ability to work with multiple language projects, the code you see in listing 5 will work perfectly with the Web Methods we have seen in this chapter, even though they are written in different languages.
In listing 6, you can see the equivalent code in Java and in listing 7, in C#.
Listing 6 - Invoking a WebMethod from a MorfikJ language Form.
package Form2;
public class Form2 extends Form
{
published TextEdit OpTxt1;
published TextEdit OpTxt2;
published ComboBox OperatorCombo;
published Button EqualsButton;
published PaintBox PaintBox1;
published TextLabel ResultLabel;
published message void EqualsButtonClick(TDOMEvent Event)
{
RunWebMethod("MathProcessor", "\"Operand1=" + OpTxt1.Text + "\"," +
"\"Operand2=" + OpTxt2.Text + "\"," +
"\"theOperator=" + OperatorCombo.Text +
"\"");
}
}
Listing 7 - Invoking a WebMethod from a C# language Form.
namespace Form3
{
public class Form3 : Form
{
published TextEdit OpTxt1;
published TextEdit OpTxt2;
published ComboBox OperatorCombo;
published Button EqualsButton;
published PaintBox PaintBox1;
published TextLabel ResultLabel;
published message void EqualsButtonClick(TDOMEvent Event)
{
RunWebMethod("MathProcessor", "\"Operand1=" + OpTxt1.Text + "\"," +
"\"Operand2=" + OpTxt2.Text + "\"," +
"\"theOperator=" + OperatorCombo.Text +
"\"");
}
}
}
It is interesting to observe that due to the fact that C# and Java have very similar syntaxes, the line that invokes the WebMethod is exactly the same in both languages.
[edit] Beware: Asynchronous Platform
As you might have noticed navigating on the Internet, when you open a page in the browser, several things seem to happen at the same time. As the text is downloaded, so are the images which are shown as their download completes.
All action within the browser happens in an asynchronous manner. No action blocks another from taking place simultaneously. So while picture A is being downloaded, so are pictures B, C and D. Whichever picture has its download concluded first, will then be shown immediately.
It is very important to keep in mind that though a call to the RunWebMethod function will return immediately, the desired results might not have yet been achieved since what really happened is that an asynchronous call was dispatched to the server part of your application. As soon as that asynchronous call is returned by the server-side execute method, then the browser side HandleResponse method will be invoked, closing the full cycle of WebMethod invocation.
[edit] Using WebMethods to Authenticate Users
So far, we have gone through several different ways of calling a very simple WebMethod. In order to get a better idea of what a WebMethod can do it will be interesting to look at a more complex example. In Listing 8, I have included the source code for the server side of a WebMethod that looks up usernames and passwords in a table and matches them in order to authenticate user access to an application. In listings 9 and 10 you will be able to see the browser side code for this WebMethod and the form which invokes the WebMethod, respectively.
Listing 8 – Server side code of a Web Method that does user authentication.
Unit UserLogin;
Interface
Type
UserLogin = Class(WebMethod)
UserName : String;
Password : String;
Authorized : Boolean;
UserID : Integer;
CompleteName : String;
Private
{ Private declarations }
Public
{ Public declarations }
Procedure Execute; override;
End; ['Published=False'];
Implementation
Procedure UserLogin.Execute;
Var
UserRS : TRecordSet;
SQLstr : string;
Begin
{Setup the SQL command to lookup the UserName and Password.}
SQLstr := 'SELECT "UserID", "Name" FROM "tbUser" where ' +
'"UserName" = ''' + UserName + ''' and ' +
'"Password" = ''' + Password + '''';
{Create the recordset with the SQL command.}
UserRS := DefaultDBConnection.CreateRecordSet(SQLStr);
UserRS.Prepare;
UserRS.Active := True;
UserRS.First;
Authorized := False;
UserID := -1;
CompleteName := '';
if not (UserRS.Bof and UserRS.Eof) then
begin
{if a corresponding entry was found the user is authenticated.}
Authorized := True;
UserID := UserRS.FieldByName('"UserID"').AsInteger;
CompleteName := UserRS.FieldByName('"Name"').AsString;
End;
UserRS.Free;
End;
End.
Observe that while the server side of the WebMethod does the actual validation, it is browser side which triggers the response in the application’s interface and stores the complete name of the user, and his username, in a browser side global variable.
Listing 9 – Browser side code of a WebMethod that does user authentication.
Unit UserLogin;
Interface
Type
UserLogin=Class(WebMethod)
UserName : String;
Password : String;
Authorized : Boolean;
UserID : Integer;
CompleteName : String;
Private
{ Private declarations }
Public
{ Public declarations }
Procedure HandleResponse; override;
End;
Implementation
Procedure UserLogin.HandleResponse;
Begin
gUserID := UserID;
gCompleteName := CompleteName;
if Authorized then {test value of parameter returned from server side}
begin
{if the user is authorized display welcome message.}
OpenForm('frmMessage', 'Index:sbfCurrentForm',
'"prmTitle=Welcome",' +
'"prmMessage='+ gCompleteName + '",' +
'"prmAuxMessage=Select a project to start working",' +
'"prmFormToOpen=frmProjectList"' );
OpenForm('frmMenuOptions', 'Index:sbfMenu', '');
end
else
ShowMessage('Login Failed.');
{if the user is not authorized, display an error message.}
End;
End.
Listing 10 – Browser side code of a Form which invokes the UserLogin WebMethod.
Unit frmLogon;
Interface
Type
frmLogon=Class(Form)
TextLabel_DocumentHeader : TextLabel;
lblUserName : TextLabel;
txtUserName : TextEdit;
txtPassword : TextEdit;
lblPassword : TextLabel;
btnOk : Button;
Container1 : Container;
Procedure btnOkClick(Event: TDOMEvent); Message;
Private
{ Private declarations }
Public
{ Public declarations }
End;
Implementation
Procedure frmLogon.btnOkClick(Event: TDOMEvent);
Begin
RunWebService('UserLogin','"UserName=' + txtUserName.Text + '",' +
'"Password=' + txtPassword.Text + '"');
End;
End.
[edit] Publishing WebMethods for External Consumption
When you create a WebMethod in your application, by default, it will not be included in the WSDL (Web Service Description Language) file that Morfik WebOS AppsBuilder generates at compile type. This essentially means that only your application will know how to use that method, since its interface definition will not be made available in the WSDL file. If you wish to make a WebMethod available for external consumption all you need to do is change the value of the Published metadata attribute for the WebMethod derived class you are creating. If you look closely at listings 1 and 8, you will see this metadata attribute appearing right after the class declaration.
If you change from the default value:
['Published=False'];
to
['Published=True'];
This WebMethod will be included in the WSDL file which Morfik tools generate at compile time. Always look for your .wsdl file in the same folder where your executable is being generated.
[edit] Importing and Consuming External Web Services
Morfik makes using external Web Services, very easy. The only thing you need to start, is to have the WSDL file of the service you wish to use. For the sake of simplicity, I have chosen to import the WSDL file which was generated for the math sample we just created, in this chapter. In Figure 4 you can see the Import Web Services option, under the Project menu.
This wizard makes it extremely easy for you to import any web service you want (provided you have access to its WSDL definition file), into your project.
Once the wizard is started, it will ask for the WSDL file that describes the service to be imported, as can be seen in Figure 5.
Once you have selected the WSDL file the wizard will display all the methods found in the service description, with their respective parameters, as shown in Figure 6.
After you have completed the Import Web Service wizard, the IDE will have generated a module with the classes required to correctly call out to the imported methods in as easy a manner as possible. You can see the code of the module for these methods in Listing 11.
Listing 11 – Code for the automatically generated interface to the imported services
Unit MathTestService;
Interface
Uses
SystemSerialiser,
SystemInternet;
Type
TMFK_DBStatus =
(
dbsModified,
dbsDeleted,
dbsNew,
dbsUnChanged
);
TMathProcessor = Class;
TMathProcessorResponse = Class;
TMathProcessor2 = Class;
TMathProcessor2Response = Class;
TMathProcessorResponse = Class(TSerializable)
theResult: double;
Status_1 : longint;
Procedure Serialize(Serializer: TSerializer); Override;
Procedure DeSerialize(Serializer: TSerializer); Override;
End;
TMathProcessor2 = Class(TSerializable)
Operand1 : double;
Operand2 : double;
theOperator: string;
Procedure Serialize(Serializer: TSerializer); Override;
Procedure DeSerialize(Serializer: TSerializer); Override;
End;
TMathProcessor2Response = Class(TSerializable)
theResult: double;
Status_1 : longint;
Procedure Serialize(Serializer: TSerializer); Override;
Procedure DeSerialize(Serializer: TSerializer); Override;
End;
TMathProcessor = Class(TSerializable)
Operand1 : double;
Operand2 : double;
theOperator: string;
Procedure Serialize(Serializer: TSerializer); Override;
Procedure DeSerialize(Serializer: TSerializer); Override;
End;
TMathTestServiceSoapIntf = Class(TSoapHttpClient)
Procedure MathProcessor (Operand1 : double; Operand2 : double;
theOperator : string; Var theResult : double;
Var Status_1 : longint); Virtual;
Procedure MathProcessor2(Operand1 : double; Operand2 : double;
theOperator : string; Var theResult : double;
Var Status_1 : longint); b;
End;
Implementation
Const
TMFK_DBStatus_EnumValues =
'dbsModified|'+
'dbsDeleted|'+
'dbsNew|'+
'dbsUnChanged';
{.................... TMathProcessor ....................}
Procedure TMathProcessor.Serialize(Serializer: TSerializer);
Begin
Inherited Serialize(Serializer);
Serializer.WriteDouble('Operand1 xsi:type="xsd:double"',Operand1);
Serializer.WriteDouble('Operand2 xsi:type="xsd:double"',Operand2);
Serializer.Writestring('theOperator xsi:type="xsd:string"',theOperator);
End;
Procedure TMathProcessor.DeSerialize(Serializer: TSerializer);
Begin
Inherited DeSerialize(Serializer);
Serializer.ReadDouble('Operand1 xsi:type="xsd:double"',Operand1);
Serializer.ReadDouble('Operand2 xsi:type="xsd:double"',Operand2);
Serializer.Readstring('theOperator xsi:type="xsd:string"',theOperator);
End;
{.................... TMathProcessorResponse ....................}
Procedure TMathProcessorResponse.Serialize(Serializer: TSerializer);
Begin
Inherited Serialize(Serializer);
Serializer.WriteDouble('theResult xsi:type="xsd:double"',theResult);
Serializer.Writeinteger('Status xsi:type="xsd:int"',Status_1);
End;
Procedure TMathProcessorResponse.DeSerialize(Serializer: TSerializer);
Begin
Inherited DeSerialize(Serializer);
Serializer.ReadDouble('theResult xsi:type="xsd:double"',theResult);
Serializer.Readinteger('Status xsi:type="xsd:int"',Status_1);
End;
{.................... TMathProcessor2 ....................}
Procedure TMathProcessor2.Serialize(Serializer: TSerializer);
Begin
Inherited Serialize(Serializer);
Serializer.WriteDouble('Operand1 xsi:type="xsd:double"',Operand1);
Serializer.WriteDouble('Operand2 xsi:type="xsd:double"',Operand2);
Serializer.Writestring('theOperator xsi:type="xsd:string"',theOperator);
End;
Procedure TMathProcessor2.DeSerialize(Serializer: TSerializer);
Begin
Inherited DeSerialize(Serializer);
Serializer.ReadDouble('Operand1 xsi:type="xsd:double"',Operand1);
Serializer.ReadDouble('Operand2 xsi:type="xsd:double"',Operand2);
Serializer.Readstring('theOperator xsi:type="xsd:string"',theOperator);
End;
{.................... TMathProcessor2Response ....................}
Procedure TMathProcessor2Response.Serialize(Serializer: TSerializer);
Begin
Inherited Serialize(Serializer);
Serializer.WriteDouble('theResult xsi:type="xsd:double"',theResult);
Serializer.Writeinteger('Status xsi:type="xsd:int"',Status_1);
End;
Procedure TMathProcessor2Response.DeSerialize(Serializer: TSerializer);
Begin
Inherited DeSerialize(Serializer);
Serializer.ReadDouble('theResult xsi:type="xsd:double"',theResult);
Serializer.Readinteger('Status xsi:type="xsd:int"',Status_1);
End;
{.................... MathTestServiceSoapIntf ....................}
Procedure TMathTestServiceSoapIntf.MathProcessor(Operand1 : double; Operand2 : double; theOperator : string; Var theResult : double; Var Status_1 : longint);
Begin
BeginInvoke('http://localhost:9119/?cls=soap',
'MathProcessor xmlns="http://tempuri.org/"',
'MathProcessorResponse xmlns="http://tempuri.org/"',
'MathProcessor');
Try
Try
RequestBody.WriteDouble('Operand1 xsi:type="xsd:double"', Operand1);
RequestBody.WriteDouble('Operand2 xsi:type="xsd:double"', Operand2);
RequestBody.Writestring('theOperator xsi:type="xsd:string"',
theOperator);
Invoke();
ReplyBody.ReadDouble('theResult xsi:type="xsd:double"', theResult);
ReplyBody.Readinteger('Status xsi:type="xsd:int"', Status_1);
Except
Raise;
End
Finally
EndInvoke();
End
End;
Procedure TMathTestServiceSoapIntf.MathProcessor2(Operand1 : double;
Operand2 : double;
theOperator : string;
Var theResult : double;
Var Status_1 : longint);
Begin
BeginInvoke('http://localhost:9119/?cls=soap',
'MathProcessor2 xmlns="http://tempuri.org/"',
'MathProcessor2Response xmlns="http://tempuri.org/"',
'MathProcessor2');
Try
Try
RequestBody.WriteDouble('Operand1 xsi:type="xsd:double"', Operand1);
RequestBody.WriteDouble('Operand2 xsi:type="xsd:double"', Operand2);
RequestBody.Writestring('theOperator xsi:type="xsd:string"',
theOperator);
Invoke();
ReplyBody.ReadDouble('theResult xsi:type="xsd:double"', theResult);
ReplyBody.Readinteger('Status xsi:type="xsd:int"', Status_1);
Except
Raise;
End
Finally
EndInvoke();
End
End;
Begin
End.
This unit (Listing 11) has a good quantity of auxiliary and support code which is not of much interest to the user of services. From that listing what should mainly interest the programmer, who is a user (consumer) of the web service, is a class that offers two methods, each tied to a "function" (a web method, by its own right) of the service. You can see this classes interface below:
TMathTestServiceSoapIntf = Class(TSoapHttpClient)
Procedure MathProcessor (Operand1 : double; Operand2 : double;
theOperator : string; Var theResult : double;
Var Status_1 : longint); Virtual;
Procedure MathProcessor2(Operand1 : double; Operand2 : double;
theOperator : string; Var theResult : double;
Var Status_1 : longint); Virtual;
End;
Careful observation of this code will undoubtedly reveal that this class’ methods are, in fact, an exact representation of what WebMethods we, originally, added to our application
[edit] Calling the Imported Web Service
Once the Web Service has been imported into your project, calling it up is quite simple. For the sake of simplicity I created a copy of our WebMethod test application with a renamed WebMethod: MathRequester. The main difference between this application and the original one is that the MathRequester WebMethod does not process the operations; it forwards the request to the original application, now running as a service.
Only the name of the WebMethod was changed and its server side code. The code you see in Listing 12 is that of the Server side of the MathRequester Web Method.
Listing 12 – Server side code calling out to the imported Web Service.
Unit MathRequester;
Interface
Type
MathRequester=Class(WebMethod)
Operand1 : Double;
Operand2 : Double;
theOperator : String;
theResult : Double;
Status : Integer;
Private
{ Private declarations }
Public
{ Public declarations }
Procedure Execute; override;
End; ['Published=False'];
Implementation
Uses
MathTestService;
Procedure MathRequester.Execute;
Var
MathInt: TMathTestServiceSoapIntf;
Begin
MathInt := TMathTestServiceSoapIntf.Create;
Try
MathInt.MathProcessor (Operand1, Operand2, theOperator, theResult, Status);
Finally
MathInt.Free;
End;
End;
End.
You will notice that this service (MathRequester) has the same parameters as the remote target service (MathProcessor). This is necessary since the information is just going through this service, but it also makes it quite easy to handle the remote call and the return of the result (out) values to the browser side of your applications.
[edit] Wrapping it up
As we have just seen, WebMethods can be used to provide simple functionality which takes processing from the browser to the server or they can be used to lookup information from a database, returning such information to Forms in the browser side of the application. These are, however, just a few possibilities. WebMethods are a very interesting construct within Morfik tools and can be used for very different purposes.
By creating WebMethods you can make available, to 3rd parties, certain functionalities of your online system or create services which will be centrally available for use by several different applications.


