Creating Web Methods and using them in your application

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.

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.

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.

creating-building-webservices-parameter-editor.png
Figure 1 Web Method parameter editor in the Morfik development environment.

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.

creating-building-webservices-wizard-parameters.png
Figure 2 Creating a WebMethod and its parameters through the Create Web Method Wizard.

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 written two examples: one which uses a WebMethod to perform simple mathematical operations, and another which uses a WebMethod to calculate the price of a given number of books in the BookCollector sample project.

Server Side Code

As previously mentioned, usually the server side code of a WebMethod does most of its heavy work.

In our first example, math operations are performed on the server side and sent back to the browser side of the application. In Listing 1 you can see the server-side code of the webmethod.

Listing 1 – Server side code of the MathProcessor WebMethod.

FX Code

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.


Our second example is based on the BookCollector sample project. In Form2 suppose we wish to add a feature that allows the user to type in the number of copies of the book that he/she wishes to purchase, and have the total price displayed in a TextLabel. We write a webmethod GetTotalPrice is written for this purpose. GetTotalPrice takes three parameters: "MFK$GUID" (the value of the MFK$GUID field in the Books table), NumberOfCopies (the number of copies the customer wishes to purchase) and BandIndex (the index of the current form band; this is needed so that when the webmethod returns, it knows in which band to display the result). GetTotalPrice returns the result in the parameter TotalPrice. In Listing 2 you can see the server-side code of the webmethod.

Listing 2 – Server side code of the GetTotalPrice WebMethod.

FX Code

Unit GetTotalPrice;
 
Interface
 
Type
GetTotalPrice = Class(WebMethod)
    "MFK$GUID"     : String;
    NumberOfCopies : Integer;
    BandIndex      : Integer;
    TotalPrice     : Currency;
  Private
    { Private declarations }
  Public
    { Public declarations }
    Procedure Execute; override;
End;
 
Implementation
 
Procedure GetTotalPrice.Execute;
Var
    SQL        : String;
    RecordSet  : TRecordSet;
Begin
    TotalPrice := 0.0;
 
    SQL        := 'SELECT "UnitPrice" FROM "Books" WHERE "MFK$GUID"=:"MFK$GUID"';
    RecordSet  := DefaultDBConnection.CreateRecordSet(SQL);
    Try
        RecordSet.Prepare();
        RecordSet.ParamByName('MFK$GUID').AsString := "MFK$GUID";
        RecordSet.First;
        If Not RecordSet.EOF Then
            TotalPrice := NumberOfCopies * RecordSet.FieldByName('UnitPrice').AsCurrency;
    Finally
        DefaultDBConnection.DestroyRecordSet(RecordSet);
    End;
End;
 
End.

 

Note: If you need to specify a parameter for a RecordSet as holding a NULL value, you can do so by setting its IsNull property in the same way that the AsString property is being set in the above sample.

Browser Side Code

The browser side of a 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. The browser side HandleResponse method is responsible for displaying the results.

The MathProcessor webmethod displays its results in a textlabel in the Index form. You can see the code that does this in Listing 3.

Listing 3 – Browser side code of the MathProcessor WebMethod.

FX Code

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.

math-project-run.png
Figure 3: MathProcessor WebMethod test application at run time.


The GetTotalPrice webmethod displays its results in TotalPriceTextLabel in Form2. Because Form2 is a data-bound continuous form, the HandleResponse method must make sure the result is displayed in the correct band. You can see how it does this in Listing 4.

Listing 4 – Browser side code of the GetTotalPrice WebMethod.

FX Code

Unit GetTotalPrice;
 
Interface
 
Type
GetTotalPrice = Class(WebMethod)
    "MFK$GUID"     : String;
    NumberOfCopies : Integer;
    TotalPrice     : Currency;
    BandIndex      : Integer;
  Private
    { Private declarations }
  Public
    { Public declarations }
    Procedure HandleResponse; override;
End;
 
Implementation
 
Uses
    Form2;
 
Procedure GetTotalPrice.HandleResponse;
Var
    f : Form2;
Begin
    f := Form2(XApp.Forms['Form2']);
    If f <> Nil Then
    Begin
        f.TotalPriceTextLabel.BandIndex := BandIndex;
        f.TotalPriceTextLabel.Caption   := CurrencyToLocaleString(TotalPrice, 'c');
    End;
End;
 
End.

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 3 could be achieved, with all the logic on the Browser side, if we changed the browser side to be as is shown in Listing 5. 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 5 – WebMethod’s logic implemented in the Browser side.

FX Code

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.

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?

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 6 you can see the source code for the simple test Form, which invokes the MathProcessor WebMethod on the click of a button.

Listing 6 – Invoking the MathProcessor WebMethod from Pascal, Basic and C# language Forms.

FX Code

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.


In Listing 7 you can see the source code for Form2, which invokes the GetTotalPrice WebMethod on the click of a button.

Listing 7 – Invoking the GetTotalPrice WebMethod from Pascal, Basic and C# language Forms.

FX Code

Unit Form2;
 
Interface
 
Type
Form2 = Class(Form)
    Container1          : Container;
    Container4          : Container;
    TextLabel3          : TextLabel;
    TextLabel9          : TextLabel;
    TextLabel10         : TextLabel;
    TextLabel12         : TextLabel;
    TextLabel23         : TextLabel;
    TextLabel24         : TextLabel;
    TextLabel2          : TextLabel;
    TextLabel7          : TextLabel;
    TextLabel4          : TextLabel;
    Image3              : Image;
    Container3          : Container;
    TextLabel5          : TextLabel;
    TextLabel6          : TextLabel;
    TextLabel11         : TextLabel;
    Image2              : Image;
    PriceLabel          : TextLabel;
    TextEdit1           : TextEdit;
    Button1             : Button;
    TotalPriceTextLabel : TextLabel;
    TextLabel8          : TextLabel;
    Procedure WebFormBeforeDBNavigate(Action: TDBNavigateAction; Var Cancel: Boolean); Message;
    Procedure Button1Click(Event: TDOMEvent); Message;
  Private
    { Private declarations }
  Public
    { Public declarations }
End;
 
Implementation
 
Procedure Form2.WebFormBeforeDBNavigate(Action: TDBNavigateAction; Var Cancel: Boolean);
Begin
    If Action = naNextPage Then
        Cancel := StartingOffset + PageSize >= RecordCount;
End;
 
Procedure Form2.Button1Click(Event: TDOMEvent);
Var
    Params : String;
Begin
    TextLabel8.BandIndex := Button1.BandIndex;
    TextEdit1 .BandIndex := Button1.BandIndex;
    Params := '"MFK$GUID='       + TextLabel8.Caption           + '",' +
              '"NumberOfCopies=' + TextEdit1.Text               + '",' +
              '"BandIndex='      + Button1.BandIndex.ToString() + '"';
    RunWebMethod('GetTotalPrice', Params);
End;
 
End.


For an example of how this WebMethod could be used in modules written in other language syntaxes, look at the code in Listings 6 and 7. You can see the code necessary to invoke the same MathProcessor WebMethod from a Form in Morfik Basic syntax.

Due to Morfik’s ability to work with multiple language projects, the code you see in Listing 6 and 7 will work perfectly with the Web Methods we have seen in this chapter, even if they are written in different languages.

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 a WebMethod's invocation.

WebMethods in Action

So far, we have gone through how to 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.

Writing Code for Data Manipulation

Morfik allows you to write code on the server side so that you can handle direct data manipulation. This is very useful in several different situations: such as when you want to update information stored in t more than one table at the same time and when you need to have a recurring process which is not started in response to direct end user action. All server side code that can be invoked from the browser in a Morfik application is implemented as a Web Method. This can also be quite useful for the implementation of published Web Service interfaces to the logic of your application. Read more...


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

 ['WSPublished=False'];

to

 ['WSPublished=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.

Creating a Web Services API with Web Methods

While the visually created Web Method is quite useful, and can meet most needs of the developer, if an application will publish a large quantity of Web Methods it can become troublesome to manage. Also, visually created Web Methods are restricted to having parameters of the basic data types such as String, Integer and double.

When planning to create a full fledged API for offering services through a Web Services interface the developer can opt to create the Web Methods in code, in any server side module of the application. An experienced developer should be able to take advantage of the fact that with all the required classes in the same module it becomes easier to reuse some code that is created for one Web Method, in another.

The following code listings show examples of how to declare Web Methods including some special metadata tags that must be used when declaring them in a regular module. No implementation is present for any of the Web Methods, only the class declarations or with their method headers.

Listing 8 - Sample declaration of Web Methods in a regular module

FX Code

Unit Module1;
 
Interface
 
Uses
   SystemSerialiser,
   SystemWebMethod;
 
Type
Function1 = Class(WebMethod)
   s       : String;         ['WSPublished=true','WSFieldKind=in/out'];
   k       : String;         ['WSPublished=true','WSFieldKind=in'];
   z       : String;         ['WSPublished=true','WSFieldKind=out'];
   Procedure Execute; Override;
End; ['WSPublished=true'];
 
Function2 = Class(WebMethod)
   pHeaderParam: String;         ['WSPublished=true','WSFieldKind=in/out','WSHeader=true'];
   Procedure Execute; Override;
End; ['WSPublished=true'];
 
Function3 = Class(WebMethod)
   StrLst : List of String;         ['WSPublished=true','WSFieldKind=in/out','WSHeader=false'];
   Procedure Execute; Override;
End; ['WSPublished=true'];
 
TStr = Class(TSerializable)
   S : String;
   Constructor Create(a : String);
End;
 
Function4 = Class(WebMethod)
   StrLst : List of TStr;         ['WSPublished=true','WSFieldKind=in/out','WSHeader=false'];
   Procedure Execute; Override;
End; ['WSPublished=true'];

Metadata Tags for Coding Web Methods

When you are creating a Web Method in code, without the benefit of the Visual editor for Web Methods, which lets you specify all parameters, their types and behaviors, you need to enter that information directly in your code.

There are two ways to apply tags: to the class and to specific member of the class. The only tag you need to apply to the class as whole is the WSPublished tag which must be set to True for the class to be included in the .WSDL file of the project that is being created, as previously shown and as can be seen in the listing immediately above.

There are several tags that can be applied to each member variable of a Web Method class, some of which are mandatory for variables which will function as parameters. Each variable that will function as a parameter must have the WSPublished and WSFieldKind tags associated with them. Again, the WSPublished tag must be set to True and the WSFieldKind tag must be set to one of three possible values: in, out, in/out.

In addition to these two tags you can add a third tag: WSHeader. If WSHeader is set to True the associated parameter will be added to the Web Method call's header. By default, if WSHeader is not informed in a parameter's associated metadata tags it is assumed to be False.

Below is an example of what the metadata tags that should be associated to any member variable of a Web Method class that will function as a parameter for the Web Method.

['WSPublished=true','WSFieldKind=in/out','WSHeader=false'];

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.

Related Topics

Back to top