Disponibilizando métodos de uma classe como Server Methods sem usar TServerModule em DataSnap

Hoje certamente você tem diversas classes contendo regras de negócios que poderiam ser melhor aproveitas em uma aplicação multicamada desenvolvida em Delphi. Por meio dos Server Methods é possível fazer isso tranquilamente.

Para uma classe ser disponibilizada como Server Methods é necessário:

  • Descender de TPersistent
  • Ter a diretiva {$MethodInfo ON}, esta diretiva permite ao DataSnap obter informações da classe a partir da RTTI
  • Estar registrada através do componente DSServerClass

Abaixo exemplo de uma classe que não é descendente de TDSServerModule e sim de TPersistant, podemos assumir que esta classe já existia anteriormente e que agora queremos reusar em nosso servidor DataSnap

unit User;

interface

uses
  BaseServerClass,
  Classes,
  DBXCommon,
  SysUtils,
  Dialogs,
  MainServerModule;

type
{$METHODINFO ON}
  TUser = class(TPersistent)
  private

  public
    constructor Create;
    destructor Destroy; override;

    procedure AddUser(FirstLastName, Login, Password: String);

    function IsValidUser(Login, Password: String): Boolean;

    procedure DisableUser(Login: String);
    procedure EnableUser(Login: String);

  end;

implementation

uses
  ServerContainer;

{ TUser }

procedure TUser.AddUser(FirstLastName, Login, Password: String);
var
  Comm: TDBXCommand;
begin

  if (FirstLastName = '') then
    raise Exception.Create('First/Last name is required');

  if (Login = '') then
    raise Exception.Create('Login is required');

  if (Password = '') then
    raise Exception.Create('Password is required');

  Comm := FDbxConnection.CreateCommand;

  Comm.Text :=
    'Insert Into Users (NAME, LOGIN, PASSWORD, ACTIVE ) Values (' + QuotedStr
    (FirstLastName) + ',' + QuotedStr(Login) + ',' + QuotedStr(Password)
    + ', true)';
  Comm.ExecuteQuery;

  FreeAndNil(Comm);

end;

constructor TUser.Create;
begin
  FDbxConnection := DMServerContainer.DataSnap_Server_Log.DBXConnection;
end;

destructor TUser.Destroy;
begin

  inherited;
end;

procedure TUser.DisableUser(Login: String);
var
  Comm: TDBXCommand;
begin

  if (Login = '') then
    raise Exception.Create('Login is required');

  Comm := FDbxConnection.CreateCommand;

  Comm.Text := 'Update Users Set ACTIVE = False Where LOGIN = ' + QuotedStr
    (Login);
  Comm.ExecuteQuery;

  FreeAndNil(Comm);

end;

procedure TUser.EnableUser(Login: String);
var
  Comm: TDBXCommand;
begin

  if (Login = '') then
    raise Exception.Create('Login is required');

  Comm := FDbxConnection.CreateCommand;

  Comm.Text := 'Update Users Set ACTIVE = True Where LOGIN = ' + QuotedStr
    (Login);
  Comm.ExecuteQuery;

  FreeAndNil(Comm);

end;

function TUser.IsValidUser(Login, Password: String): Boolean;
var
  Comm: TDBXCommand;
  Reader: TDBXReader;
begin
  if (Login = '') then
    raise Exception.Create('Login is required');

  if (Password = '') then
    raise Exception.Create('Password is required');

  Comm := FDbxConnection.CreateCommand;

  Comm.Text := 'Select ACTIVE From Users Where LOGIN = ' + QuotedStr(Login)
    + ' and PASSWORD = ' + QuotedStr(Password);

  Reader := Comm.ExecuteQuery;

  if Reader.Next then
  begin
    Result := Reader.Value[0].GetBoolean;
  end
  else
    Result := False;

  Reader.Close;
  FreeAndNil(Reader);
  FreeAndNil(Comm);

end;

end.

Quer saber mais sobre DataSnap, clique aqui.

9 respostas
  1. Bruno Pegoraro
    Bruno Pegoraro says:

    E se um desses métodos remotos chamasse internamente um método de uma DLL local (no servidor de aplicação) ??
    Esse é meu caso e quanto tento invocar o método da aplicação cliente retorna o seguinte erro:

    Remote error: CoInitialize não foi chamado, ClassID: {1B72700B-9A17-35C4-B2C6-5C84A6CF7C1D}

    Responder
  2. Andreano Lanusse
    Andreano Lanusse says:

    Bruno, isso não é problema para o DataSnap, como não tenho o seu código fica difícil de entender o que está acontecendo, mas pela mensagem está dizendo que você não chamou o método CoInitialize, parece ter chamadas OLE na sua DLL, então ao subir seu servidor DataSnap execute este método.

    Responder
  3. Paulo
    Paulo says:

    Olá Andreano,

    primeiramente ótima materia, estou tentando usar seu exemplo acima com uma diferença – usar o Overload em umas das chamadas, mas o delphi nao me permite compilar o projeto retornando o sequinte erro :
    [DCC Error] User.pas(26): E1030 Invalid compiler directive: ‘OVERLOAD’

    os metodos descendidos de TPersistent não aceitam o Overload ?
    tem ideia de qual seria o problema de fazer overload em procedure e functions usando o DataSnap ?

    Obrigado.

    Responder
  4. Júlio César Ferreira (@jcmferreira)
    Júlio César Ferreira (@jcmferreira) says:

    Essa dica de como disponibilizar métodos “server methods” sem utilizar o TServerModule é perfeita! Salvou-me de muitas dúvidas ainda não respondidas…

    O ruim do DataSnap é que, uma vez nele, vc quer sempre muito mais.

    Gostaria muito de saber um pouco mais sobre a parte de autenticação de usuários, sessões via TCP/IP e controle do cache de dados. Quando surgir algo do tipo por aqui, vai ser ótimo! 😉

    Parabéns pelo blog!

    Responder
  5. Júlio César Ferreira (@jcmferreira)
    Júlio César Ferreira (@jcmferreira) says:

    Bom dia Andreano!

    Sobre essa solução na criação de ServerMethods em runtime, o registro dela através do componente DSServerClass precisa ser feito em que momento? No meu ServerContainer, que possui o DSServer ou na própria declaração da classe, como essa TUser?

    Tentei criar uma classe como a do seu exemplo, TSimpleServerClass = class(TDSServerClass), e instanciei a mesma no meu ServerContainer. O registro de uma classe qualquer minha até funiona mas o meu cliente datasnap não consegue enxergar o provider dela…

    Existe alguma coisa a mais para ser feita ou de forma diferente para que isso funcione?

    Responder
  6. José Francisco
    José Francisco says:

    Boa Noite,

    Tenho dúvida quanto a concorrência na execução dos servermethods pela parte dos clients
    (*caso dos conectores em android)

    Porque ocorre falhas como *access violation quando dois clientes executam ao mesmo tempo um servermethod ?

    Qual a melhor maneira pra se trabalhar com essa concorrência ?

    E se é possível criar uma única aplicação DataSnap com WebBroker + Mobile Conectors ?

    Obrigado,

    Responder
  7. DOUGLAS
    DOUGLAS says:

    Achei bacana mesmo o artigo.
    Porém não estou conseguindo chamar do lado do cliente o método.
    Alguem poderia me dar um exemplo de como eu poderia fazer essa chamada?

    Responder

Deixe uma resposta

Want to join the discussion?
Feel free to contribute!

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *


Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.