Dispatch Notifier (Delphi)

Overview

This sample demonstrates how to customize the invocation and execute user code on the server side before the service method is invoked. The IRODispatchNotifier is a special interface that the TROInvoker classes recognize. If your server side object implements it, the IRODispatchNotifier.GetDispatchInfo method is called before the target method is invoked.

Getting Started

  • Build both client and server projects.
  • Launch the server application; you can use the menu command Tools -> Remoting SDK -> Launch Server Executable.
  • Launch the client application.
  • Choose the channel type, TCP or HTTP, enter any text message to the field and click the Send button.

  • Check the server's log windows to see the invokation information displayed.

Examine the Code

The client side is nothing special so let's examine the server side code.

  • The service class implements the IRODispatchNotifier interface to enable advanced dispatching features. It also implements the custom interface ITestInvokeInterface to publish the DoThis and DoThat methods. This way, the service functionality is expanded even more.
  { TDispatchNotifierService }
  TDispatchNotifierService = class(TRORemotable, IDispatchNotifierService, IRODispatchNotifier, ITestInvokeInterface)
  private
  protected
    { IRODispatchNotifier }
    procedure GetDispatchInfo(const aTransport: IROTransport; const aMessage: IROMessage);

    { ITestInvokeInterface }
    procedure DoThis;
    procedure DoThat;

    { IDispatchNotifierService methods }
    procedure SendMessage(const aMessage: UnicodeString);
  end;
  • Examine the implementation of the GetDispatchInfo method, which is called before any service method is invoked. The results of this method execution can be seen in the log window:
procedure TDispatchNotifierService.GetDispatchInfo(
  const aTransport: IROTransport; const aMessage: IROMessage);
var
  tcpinfo: IROTCPTransport;
  textmessage: UnicodeString;
  streamaccess: IROStreamAccess;
begin
  if Supports(aTransport, IROTCPtransport, tcpinfo) then DispatchNotifierServerMainForm.Log('Client ' + tcpinfo.GetClientAddress + ' connected!');

  with aTransport do
    DispatchNotifierServerMainForm.Log('Got a reference to a ' + GetTransportObject.ClassName);

  with aMessage do begin
    DispatchNotifierServerMainForm.Log('About to invoke ' + InterfaceName + '.' + MessageName);

    if (MessageName = 'SendMessage') then begin
      aMessage.Read('aMessage', TypeInfo(UnicodeString), textmessage, []);
      DispatchNotifierServerMainForm.Log('The text message was "' + textmessage + '"');

      { New RemObjects 4.0: now you can reset the position of the message stream }
      if Supports(aMessage, IROStreamAccess, streamaccess) then streamaccess.Stream.Position := 0;
    end;
  end;
  DispatchNotifierServerMainForm.Log('');
end;
  • After GetDispatchInfo is called, the internal invoker facility calls TROInvoker.BeforeInvoke; this method is requested to be invoked by the client, then TROInvoker.AfterInvoke is called. Before and after the invoke methods are overridden. The method code has access to the service instance via the anInstance parameter, we use it to test if the ITestInvokeInterface is supported by the service and call some methods if it is:
procedure TMyInvoker.AfterInvoke(aMethodPtr: TMessageInvokeMethod;
  const anInstance: IInterface; const aFactory: IROClassFactory;
  const aMessage: IROMessage; const aTransport: IROTransport;
  anException: Exception);
var
  itestintf: ITestInvokeInterface;
begin
  inherited;

  if Supports(anInstance, ITestInvokeInterface, itestintf) then itestintf.DoThis;
end;

procedure TMyInvoker.BeforeInvoke(aMethodPtr: TMessageInvokeMethod;
  const anInstance: IInterface; const aFactory: IROClassFactory;
  const aMessage: IROMessage; const aTransport: IROTransport);
var
  itestintf: ITestInvokeInterface;
begin
  inherited;

  if Supports(anInstance, ITestInvokeInterface, itestintf) then itestintf.DoThat;
end;
  • The final important thing to do is to make the RO library use our invoker class TMyInvoker as an invoker for the service. This is done by changing the implementation unit initialization section:
initialization
  TROClassFactory.Create('DispatchNotifierService', Create_DispatchNotifierService, TMyInvoker);

Concepts Covered