Registrando DataSnap Server Class em tempo de execução no Delphi

Sempre que estamos construindo uma aplicação DataSnap temos que registrar as classes que serão disponbilizadas para o lado cliente, o natural é utilizar o componente DSServerClass pra isso, muitas vezes queremos fazer isso em tempo de execução, abaixo segue um código exemplo de como efetuar o registro destas classes em tempo de execução.

No código abaixo a classe TSimpleServerClass herda de TDSServerClass e estende o método Create onde passamos a classe a ser registrada, seu respectivo DataSnap Server e o LifeCycle.

type

   TSimpleServerClass = class(TDSServerClass)
   private
     FPersistentClass: TPersistentClass;
   protected
     function GetDSClass: TDSClass; override;
   public
     constructor Create(AOwner: TComponent; AServer: TDSCustomServer; AClass: TPersistentClass; ALifeCycle: String); reintroduce; overload;
   end;

   procedure RegisterServerClasses(AOwner: TComponent; AServer: TDSServer);

implementation

constructor TSimpleServerClass.Create(AOwner: TComponent; AServer: TDSCustomServer; AClass: TPersistentClass; ALifeCycle: String);
begin
  inherited Create(AOwner);
  FPersistentClass := AClass;
  Self.Server := AServer;
  Self.LifeCycle := ALifeCycle;
end;

function TSimpleServerClass.GetDSClass: TDSClass;
begin
  Result := TDSClass.Create(FPersistentClass, False);
end;

Agora é criar uma instância de TSimpleServerClass para cada classe que contém os server methods.

Abaixo um exemplo onde são registradas 3 classes no mesmo server, com LifeCycles distintos:

procedure RegisterServerClasses(AOwner: TComponent; AServer: TDSServer);
begin
  Assert(AServer.Started = false, 'Não é possível adicionar classes com o servidor ativo');
  TSimpleServerClass.Create(AOwner, AServer, TGlobal, TDSLifeCycle.Server);
  TSimpleServerClass.Create(AOwner, AServer, TCustomer, TDSLifeCycle.Session);
  TSimpleServerClass.Create(AOwner, AServer, TObjectPool, TDSLifeCycle.Invocation);
end;

Simples e muito prático, até o próximo artigo.

24 respostas
    • Andreano Lanusse
      Andreano Lanusse says:

      A alteração que você fez não é recomendada, você assume que todas as classes são Session e além disso usa a string Session em vez do tipo TDSLifeCycle

      Responder
  1. marlon david de souza
    marlon david de souza says:

    No novo DataSnap, em uma conexão do tipo Session, eu sei que os objetos são criados apenas quando são usados (execução de algum de seus métodos), porém destruídos apenas quando a conexão é encerrada.

    Existe alguma maneira de destruir os objetos criados sem ter que fechar a conexão?

    Responder
  2. Tiago
    Tiago says:

    Adriano, por favor !
    O método Constructor da classe criada para poder ser registrada dessa forma não é executado.

    Tem alguma forma de fazer ser executado ou alguma outra forma de instanciar alguns objetos adicionados nela quando ela for instanciada pelo DataSnap ?

    O que acontece é que quero criar alguns objetos para serem utilizados pela classe servidora, porém esses não consigo instanciar por conta do método Constructor não ser chamado.

    Tem alguma idéia ?
    Muito obrigado !
    Att. Tiago

    Responder
  3. Rodrigo Martim
    Rodrigo Martim says:

    Bom dia Andreano,

    Estou efetuando o registro de minhas classes dessa forma, porem quando eu tento carregar o meu CDS ele retorna o erro.

    Remote Error: TDSCidade.AS_GetRecords method not found in the server method list.

    caso eu faça o registro utilizando o componente
    DSServerClass ele funciona perfeitamente.

    você saberia me informar o por que deste problema?

    Agradecido desde já,
    Atenciosamente,
    Rodrigo Martim.

    Responder
    • Andreano Lanusse
      Andreano Lanusse says:

      Oi Rodrigo,

      Isso acontece porque você está tentando retornar um ClientDataSet em um dos métodos e isso não é possível, na seção DataSnap do meu blog eu explico os tipos que podem ser retornados e convertidos em JSON.

      Responder
  4. Rodrigo Martim
    Rodrigo Martim says:

    Boa tarde Andreano,

    Desculpe – me pela ignorancia, porem, não consigo entender o seguinte.
    Fazendo a publicação da classe para o lado cliente utilizando o componente TDSServerClass e seu metodo OnGetClass este problema se resolve.
    O Problema apenas acontece quando a publicação para o lado cliente é realizada com a classe TSimpleServerClass,
    notei que ao registrar por este metodo, vários metodos não são publicados.

    Exemplos:
    TDSCidade.AS_ApplyUpdates TDSCidade AS_ApplyUpdates
    TDSCidade.AS_GetRecords TDSCidade AS_GetRecords
    TDSCidade.AS_DataRequest TDSCidade AS_DataRequest
    TDSCidade.AS_GetProviderNames TDSCidade AS_GetProviderNames
    TDSCidade.AS_GetParams TDSCidade AS_GetParams
    TDSCidade.AS_RowRequest TDSCidade AS_RowRequest
    TDSCidade.AS_Execute TDSCidade AS_Execute

    Aparecem apenas quando registrados pelo componente TDSServerClass

    Desculpe – me se estiver falando besteira, e muito obrigado pela ajuda.
    Atenciosamente,
    Rodrigo Martim

    Responder
  5. Andreano Lanusse
    Andreano Lanusse says:

    Rodrigo, estes métodos que você menciona são métodos relacionados a interface do IAppServer, que é usado pelo provider e clientdataset.

    Responder
  6. marcelo
    marcelo says:

    Andreano so voce pode me salvar, estou gostando demais o datasnap, porem como meu sistema é todo dinamico em BPLs preciso fazer o mesmo para o metodos do servidor, para isso criei pacotes (BPL) para cada modulo, Compra.bpl, Estoque.bpl, Venda.bpl carregado em tempo de execução com LoadPackage() assim nao preciso recompilar meu executavel do servidor para adicionar novos metodos no servidor e quando eu mudar um metodo do pacote Estoque.bpl nao preciso atualizar todo o servidor, so parar o servico colocar a nova bpl e iniciar o servico novamente, porem ja tentei de varios jeitos vincular DSServerClass dentro de um bpl carregada em tempo de execução com LoadPackage() mas nao consegui ter sucesso, existe algum bug relacionado a isso? pode enviar um exemplo? ja com pacotes carregados automaticos ja funciona, to acredito ser um BUG do datasnap, estou utilizando DELPHI XE, socorre eu. Obrigado.

    Responder
    • Francis Silva
      Francis Silva says:

      Eu fiz a mesma coisa utilizando DLLs com LoadLibrary e a classe TSimpleServerClass.

      Eu percebi que essa classe cria os componentes TSimpleServerClass no Server Datamodule (através da constatação da existência do componente na lista de componentes do Datamodule), mas apesar disso a classe e nem os seus métodos são publicados. Ou seja, os TSimpleServerClass estão criados mas não publicam nada.

      O que pode estar sendo feito de errado? Não é possível registrar e publicar métodos de classes contidas em DLLs ou BPLs ?

      Responder
  7. Rafael Pasa
    Rafael Pasa says:

    Esse seu exmplo não permite que seja publicados os Providers do Servidor DataSnap.
    Apenas podemos publicar os metdos declarados no ServerModule.
    Se você Andreano, tiver uma maneira de publicar os providers para serem ligados ao clientDataSet na App cliente, por favor disponibilize o exemplo.

    Tenho urgencia em Resolver esse problema.
    Obrigado

    Responder
  8. Rafael Pasa
    Rafael Pasa says:

    Achei a solução para publicar os provider nesse exemplo.

    mude o codigo da função GetDSClass para o codigo a abaixo.

    function TSimpleServerClass.GetDSClass: TDSClass;
    begin
    Result := TDSClass.Create(FPersistentClass, false);
    Result := TDSClass.Create(TDSProviderDataModuleAdapter, Result)
    end;

    Abraço

    Responder
  9. Rafael Alberto Pasa
    Rafael Alberto Pasa says:

    Esse codigo não publica os providers de um servermodule, ae não ajuda muito.
    Eu modifiquei uma função pra resolver o problema.
    segue o códgio abaixo.

    function TSimpleServerClass.GetDSClass: TDSClass;
    begin
    Result := TDSClass.Create(FPersistentClass, false);
    Result := TDSClass.Create(TDSProviderDataModuleAdapter, Result)
    end;

    facinho.

    Abraço

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

    Bom dia Andreano.

    Com relação ao registro de classes pelo servidor DataSnap, existe uma forma de permitir que uma classe com um método em overload possa ser registrada?

    Tentei realizar um teste com um método chamado GetImage com as assinaturas abaixo:
    GetImage( const id: Integer ): TStream; overload;
    GetImage( const login: String ): TStream; overload;

    Mas o DataSnap não aceita o registro da respectiva classe pois reclama que o método GETIMAGE já foi registrado.

    Responder
  11. Francis Lay Silva
    Francis Lay Silva says:

    Olá Andreano, excelente artigo, o seu blog é praticamente a única ou no mínimo a melhor fonte de informação sobre DataSnap.

    Estou querendo utilizar sua classe TSimpleServerClass em um projeto de um servidor DataSnap genérico, que vai servir de base para outros servidores com poucas modificações. Ele está sendo escrito em XE7. O diferencial dele é que os Server Methods vão ser carregados dinamicamente por meio de classes contidas em DLLs, bastando adicionar a DLL para o diretório específico e o servidor carrega os métodos e os registra no servidor.

    Já está tudo pronto, as DLLs são carregadas dinamicamente e as classes registradas utilizando TSimpleServerClass. Entretanto as classes registradas NÃO APARECEM na lista de classes do servidor, mas ao consultar a lista de componentes do TDatamodule usado como Server Container destas classes, todos os componentes TSimpleServerClass registrados pela DLL estão lá com as respectivas propriedades preenchidas corretamente.

    Se eu utilizo o mesmo comando TSimpleServerClass diretamente no DataModule a classe é registrada e publicada normalmente, então a rotina está correta, o problema acontece quando a classe é registrada por dentro da DLL.

    Existe alguma incompatibilidade conhecida do DataSnap com DLLs ? Você tem alguma idéia do que pode ser o problema?

    Fico grato por qualquer dica que puder me fornecer pois já tentei de tudo e não consigo contornar o problema.

    Obrigado.

    Responder

Trackbacks & Pingbacks

  1. […] Embarcadero Tweet Já faz algum tempo que publiquei aqui no blog sobre registro de DataSnap Server Class em tempo de execução, neste mesmo post surgiu vários comentários relacionados a não publicação dos Provider parte […]

  2. […] Este post peguei como exemplo um do Andreano Lanusse, aqui. […]

  3. […] This post was mentioned on Twitter by Andreano Lanusse, Embarcadero Asia. Embarcadero Asia said: Registrando DataSnap Server Class em tempo de execução no Delphi http://bit.ly/ea5Aic […]

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.