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

  • Async callback names are case sensitive:

In previous vesions you could register a function named "myAjaxFunc" and call it from JavaScript code as "MYAJAXFUNC" and it would work. Why it used to work and doesn't work now? Because the registered functions were kept in a TStringList which is able to do case insensitive search. Now we are using a dictionary which performs better but can only find a match if the provided string is exactly the same as the one registered. This shouldn't be an issue in the vast majority of cases. If not, please adjust your Delphi code to use exactly the same string as your JavaScript code.

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

The unregistration methods still exist but don't need to be called in the vast majority of the 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. Have also in mind that anonymous functions can't be unregistered.

  • 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 string (case sensitive) as the one registered via RegisterCallback() and (b) RegisterCallback() is correctly called by your code.

  • 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.

 

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