...Async_Ex service functions

hi, i’ve started playing around with the Async_Ex service function calls and have a few questions:

  • the create:
    class function Create(const aUrl: string; aDefaultNamespaces: string = ‘’): IProxyService_AsyncEx; overload;
    it seems that i can’t get this one to work, i do include the /BIN but i guess it does not resolve to the right channel… any prerequisites using this?

  • channel and message:
    my these be shared when using the async_ex functions or do these have to have their own channel and message?

  • the callback:

  • is this called in the main thread or do i need to foresee threaded entry?
  • can i have multiple async_ex.beginxxx calls all using the same callback?
  • if so what is the lifetime of the Endxxx call of (const aRequest: IROAsyncRequest)?
  • if i can’t use the same callback for multiple beginxxx calls, do i always nil the aRequest or not? (in the photo sample you check the intf: if aRequest = ClientForm.fDownload then ClientForm.fDownload := nil;)
  • any other things to take into account?

Hi,

Check the Phone Photo Server sample - it shows usage of AsyncEx interfaces.

You should include full URL with /Bin - it will allow to detect valid message.
general rules - you should include desired channel/message into uses section.

Channels/Messages contain code like

ROUrlSchemaParser.ProtocolHandler[URL_PROTOCOL_HTTP] := TROIndyHTTPChannel;
ROUrlSchemaParser.MessageHandler['bin'] := TROBinMessage;

it is used for detecting what channel/message should be used.
you may add registration manually for desired channel if it is missed it.

own channel/message are used for AsyncEx fro avoiding AV issues when the same data is read/wtitten from different threads.
You can retrieve channel/message from IROAsyncRequest interface.

it is called in background thread

You can use the same callback method for handling begin* methods.

for example - you have BeginSum and BeginGetServerTime methods. if same callback is used for both methods you have to call EndSum or EndGetServerTime in that callback. ofc, you can put some additional info into UserData and detect valid method, but I think better to have own callback per method.

server response is stored in object associated with IROAsyncRequest. this object is passed to your callback method.

in this sample we allow only one download request so we cancel previous one:

  if (fDownload <> nil) then fDownload.Cancel;
...
  fDownload := GetService.BeginDownloadPhoto(lItem.Name,Callback_DownloadPhoto,lItem);

so we clear fDownload once download callback was finished.

Channels/Messages contain code like

ROUrlSchemaParser.ProtocolHandler[URL_PROTOCOL_HTTP] := TROIndyHTTPChannel;
ROUrlSchemaParser.MessageHandler['bin'] := TROBinMessage;

it is used for detecting what channel/message should be used.
you may add registration manually for desired channel if it is missed it.

the uses clause is ok, but the channel does not get recognised, we use plain tcp by the way, not https, so my test url is ‘localhost:8888/BIN’
is this supposed to work?

it is called in background thread

You can use the same callback method for handling begin* methods.

so if i execute 5 beginAAA calls (so the same function) all with the same callback interface, and since the callback is being called threaded, i should include thread code that will synchronise with main thread yes? or will the the callback for the beginAAA func be like a fifo callback?

in this sample we allow only one download request so we cancel previous one:

  if (fDownload <> nil) then fDownload.Cancel;
...
  fDownload := GetService.BeginDownloadPhoto(lItem.Name,Callback_DownloadPhoto,lItem);

so we clear fDownload once download callback was finished.

no i was talking about the callback procedure which has:
finally
if aRequest = ClientForm.fDownload then ClientForm.fDownload := nil;

so this frees the iroasyncrequest but only if it was the one that was created in the beginAAA call, but why only if it is the same? since the call has ended, shouldn’t it be always freed?

you should use tcp://localhost:8888/BIN

it shouldn’t matter because you receive aRequest in callback method.
so you will have 5 background threads with

  • callback(aRequest1)
  • callback(aRequest2)
  • callback(aRequest3)
  • callback(aRequest4)
  • callback(aRequest5)

in the Phone Photo Server sample we use PostMessage for passing data from background threads to main thread.

it isn’t freed interface, it just clear private variable of TClientForm [and decrease reference count] so interface will be correctly destroyed.

ok thx for the info!

Evgeny,

consider this:
var intf : IROAsyncRequest

intf := beginAsync_ex();

intf := beginAsync_ex();

intf := beginAsync_ex();

so now i have 3 requests stored in same var intf…

callback(const aRequest: IROAsyncRequest);

  1. so this is a const param, i can’t nil this, so the async_ex object will take care of this?

  2. since i putted all beginAsync_ex() result into the same var i will have created dangling interface references yes?
    if so i need to hold some kind of list of them?
    or can i simply ignore the interface result of the beginAsync_ex call?
    in fact do i need the interface reference at all?

tia!

Hi,

No issue at all. this means that you can work only with last request.
actual IROAsyncRequest is stored internally and it will be passed to your callback as a parameter.

if you don’t need to do anything with request (check state, cancel request, etc), you can just ignore result of begin* method like

beginAsync_ex();
…
beginAsync_ex();
…
beginAsync_ex();

check TClientForm.bUploadClick:

procedure TClientForm.bUploadClick(Sender: TObject);
..
   GetService.BeginUploadPhoto(lFileName,lstr,Callback_UploadPhoto, lstr);
  end;
end;