Please remember this is a work in progress. Home » Development

Development

 

Async callbacks in IntraWeb 15.1

 

New Async callback features

Async callbacks were greatly enhanced in IntraWeb 15.1 branch. All existing IntraWeb code will work, so there is no need to change anything when updating to IW 15.1 (please check "Other changes in Async infrastructure" topic below).

Until version 15.0, this was the only Async callback method signature:

TIWCallbackMethod = procedure (aParams: TStringList) of object;

Starting with IW 15.1 there are 4 new ways to declare a callback method/function (unit IWCallBackFunc.pas):
  TIWCallbackProc0 = reference to procedure;

  TIWCallbackProc1 = reference to procedure (aParams: TStrings);

  TIWCallbackProc2 = reference to procedure (aParams: TStrings; out aResult: string);

  TIWCallbackProc3 = reference to procedure (aParams: TStrings; out aResult: string; out aHandled: Boolean);


Please note that new callback types are declared as reference to procedure (not method pointers) which allows you to use mostly any type of method/procedure as a callback, including anonymous methods.

Example:

procedure TIWForm1.IWAppFormCreate(Sender: TObject);
begin
  RegisterCallBack('myAjaxFunc',
      procedure (aParams: TStrings)
      begin
        WebApplication.ShowMessage('this is an anonymous method used as a callback');
      end
    );
end;


which is a very convenient way of declaring and registering an async callback function, specially for component writers. Now, look at TIWCallbackProc2 declaration above, and see how it can be used to simplify some AJAX calls:
procedure TIWForm1.IWAppFormCreate(Sender: TObject);
begin
  RegisterCallBack('Multiply',
      procedure (aParams: TStrings; out aResult: string)
      var
        x, y: Integer;
      begin
        x := StrToIntDef(aParams.Values['x'], 0);
        y := StrToIntDef(aParams.Values['y'], 0);
        aResult := IntToStr(x * y);
      end
    );
end;



"Multiply" function can be called from JavaScript using something as:

ajaxCall("Multiply", "&x=5&y=10", false, function(response) {alert("Result is: " + response);});
	

In the above example, the callback function receives 2 parameters named x and y, and multiply them. The result is put into aResult parameter (which is an out parameter) The difference here compared to old versions is that aResult string is returned to the browser as is, i.e. the response will contain a string representing the result of the multiplication of x by y only, nothing else. This makes much easier to interface with existing JavaScript libraries which expect specific responses (e.g. JSON strings).

The forth type of callback (TIWCallbackProc3) is the most flexible one. It allows you to set the result directly using variable aResult (as above) or still use TIWApplication.CallbackResponse object (as in IW 15.0), or yet, bypass the response completely setting aHandled parameter to True. Setting aHandled to True means that the user code is responsible for creating the reponse. In this case, IntraWeb will skip the execution of callback response code completely.

Other changes in Async infrastructure

  • RegisterCallback() method:

RegisterCallback() is now exposed as a method (actually 5 different overloads) of TIWForm class and also from TIWPageContext40 class. It is still available in TIWApplication class as in previous versions. TIWApplication.RegisterCallback() actually calls TIWForm.RegisterCallback() so there is absolutely no difference in usage.

  • Callback functions don't need to be unregistered in most cases:

The unregistration methods still exist but don't need to be called in most cases. In previous versions, TIWApplication was the "owner" of the registered callback functions, meaning that the callback would continue exist as long as the application was active. Now the owner of the callback functions is the page context (a TIWPageContext40 instance which is owned by a TIWForm instance) and all callback functions are released when the form is destroyed.

When controls are created and destroyed at runtime and insterted into existing forms, it is still required to call UnregisterCallback(). A common use case is when IWFrames are created at runtime and insterted into (parented to) existing forms. If the frame is later destroyed and the parent form is kept alive, all controls of the Frame which registered any callback method when initializing should unregister the same method before being destroyed. Failing to do so will possibly cause AV exceptions if the callback is called from an existing page (remember that the calling code lives inside the browser and parts of the JavaScript code may execute at a later time after the control on the server side has been destroyed).

The following methods are available as part of TIWApplication, TIWForm and TIWPageControl40 public interface:

    procedure UnregisterCallBack(const AName: string); overload;

    procedure UnregisterCallBack(AMethod: TIWCallbackMethod); overload;

Please notice that anonymous functions can only be unregistered using the name, not the method pointer.

 

  • Registered callbacks don't contain the form name:

In previous versions, when registering a callback, IntraWeb would concatenate the name of the (active) form (e.g. "IWForm1") and the name of the callback function (e.g. "myAjaxFunc"), transparently, and store it internally as "IWForm1.myAjaxFunc". This was necessary because the user could possibly have more than one myAjaxFunc in different forms or form instances. This is not necessary anymore, so the name of the form is not stored. If your JavaScript code uses the form name as mentioned, it will still work, so don't worry. However, when writting new code, have in mind that the name of the form is not necessary and shouldn't be used anymore.

  • IntraWeb responds with 404 when callback function is not found:

The HTTP status code returned when a callback function is not found/not registered is now 404, and not 200 as before. It makes easier to identify possible failures when calling Async functions. When this happens, please make sure that: (a) Your JavaScript code references the server method using the same identifier as the one registered via RegisterCallback() and (b) RegisterCallback() is correctly called by your code. Also, remove the name of the form from the callback registration/call, if applicable.

  • Calling RegisterCallback() from a IWForm:

Ideally, RegisterCallback() should be called from IWForm's OnCreate event handler not from OnRender() event. OnCreate only happens once for each form instance and OnRender() will trigger at least once, but possibly multiple times during form's life cycle. There is no reason to call RegisterCallback() from OnRender, once it will be called multiple times. Have in mind that, even if you register a callback function multiple times, IntraWeb will correctly handle registration and update existing references, but you are basically a waste of CPU cycles.

If you are creating controls at runtime (e.g. as part of a dynamic TIWFrame), make sure to register all callbacks during the parent Frame initialization and unregister them if the frame is destroyed before the owner form. It is not necessary to unregister callback methods if the owner form is also being destroyed.

 

Terms of Use | Privacy Statement © 2002 - 2021 Atozed Software