DataSnap 2010 – Enviando e recebendo objetos

Categories:DelphiTags: , ,

Delphi iconUma das perguntas frequentes dos usuários de Delphi 2009 e que utilizam DataSnap para criação de objetos é sobre a transferência de objetos entre cliente e servidor. No DataSnap 2009 estavamos limitados aos data types do dbxExpress, agora com o DataSnap 2010 que acompanha o Delphi 2010, isso é totalmente possível.

DataSnap 2010 traz o suporte a JSON (JavaScript Object Notation) que é uma formatação leve de troca de dados, totalmente independente de linguagem, futuramente vou comentar mais sobre JSON e suas vantagens, para começar este post irá mostrar como transferir objetos entre cliente e servidores DataSnap, sendo que ambos cliente e servidor são aplicações Delphi.

Para começar vamos definir uma classe chamada TCustomer.


unit Customer;

interface

uses
   DBXJSON, DBXJSONReflect, SysUtils;

type
   TMaritalStatus = (msMarried, msEngaged, msEligible);

TCustomer = class
    private
       FName: string;
       FAge: integer;
       FMaritalStatus: TMaritalStatus;
    public
        property Name: string read FName write FName;
        property Age: integer read FAge write FAge;
        property MaritalStatus: TMaritalStatus read FMaritalStatus write FMaritalStatus;

        function toString : string;override;
  end;

Para transferir objetos em DataSnap estes devem descender the TJSONObject, no caso de não ser um objeto descendente você terá que utilizar as classes TJSONMarshal e TJSONUnMarshal para efetuar a transformação dos objetos. Sendo assim os métodos abaixo irão efetuar a conversão dos mesmos.


unit Customer;

  function CustomerToJSON(customer: TCustomer): TJSONValue;
  var
    m: TJSONMarshal;
  begin
    if Assigned(customer) then
    begin
      m := TJSONMarshal.Create(TJSONConverter.Create);
      try
        exit(m.Marshal(customer))
      finally
        m.Free;
      end;
    end
    else
      exit(TJSONNull.Create);
  end;

  function JSONToCustomer(json: TJSONValue): TCustomer;
  var
     unm: TJSONUnMarshal;
  begin
    if json is TJSONNull then
      exit(nil);
    unm := TJSONUnMarshal.Create;
    try
      exit(unm.Unmarshal(json) as TCustomer)
    finally
      unm.Free;
    end;
  end;

Com isso temos classe TCustomer pronta para trafegar entre cliente e servidor, assim sendo basta implementar um Server Method que retorne um TJSONValue a partir da transformação de TCustomer, como o exemplo abaixo.


// protected
function TServerMethods.GetCustomer: TCustomer;
begin
  Result := TCustomer.Create;
  Result.Name := 'Pedro';
  Result.Age := 30;
  Result.MaritalStatus := msEligible;
end;

// public
function TServerMethods.GetJSONCustomer(): TJSONValue;
var
  myCustomer: TCustomer;
begin
  myCustomer := GetCustomer;
  Result := CustomerToJSON(myCustomer);
  myCustomer.Free;
end;

No lado cliente ao executar o método GetJSONCustomer será necessário efetuar a transformação de TJSONValue para TCustomer, utilizando o método JSONToCustomer.


var
  proxy: TServerMethodsClient;
  myJSONCustomer: TCustomer;
begin

  try
    proxy := TServerMethodsClient.Create(SQLConnection1.DBXConnection);
    myJSONCustomer := JSONToCustomer(proxy.myJSONCustomer);

    Button1.Caption := myJSONCustomer.ToString;
    myJSONCustomer.Free;
  finally
    SQLConnection1.CloneConnection;
    proxy.Free;
  end;
end;

Muito mais pode ser feito, como retornar Arrays de objetos, classes mais complexas, etc. Estarei abordando estes temas em futuros posts.

Download do código fonte

Posts relacionados

49 Responses to DataSnap 2010 – Enviando e recebendo objetos

  1. Responder Transferência de objetos via DataSnap « Marlon’s Weblog says:

    [...] Setembro 25, 2009 por marlonsouza Agora, no Delphi 2010, é possível transferir objetos entre entre clientes e servidores DataSnap. Leia mais a respeito no endereco http://www.andreanolanusse.com/pt/datasnap-2010-enviando-e-recebendo-objetos/ [...]

  2. Responder Retornando array de objetos no DataSnap com Delphi 2010 | Andreano Lanusse Blog says:

    [...] sequência ao tema transferência de objetos com DataSnap o qual iniciei escrevendo sobre a transferência de um simples objeto, o qual é pré-requisito para entender este artigo, neste post descrevo como transferir uma lista [...]

  3. Responder Everson Novka says:

    Olá Andreano, bem interessante esses novos recursos do Delphi 2010, a minha licença do novo Delphi deve estar chegando nessa semana, já estou aqui pirando para poder escrever meus serviços com datasnap. Alguns dias atrás eu escrevi um mini-artigo sobre exportação de dados de um dataset para um arquivo JSON utilizando versões anteriores ao Delphi 2010, utilizei a biblioteca lkjson, q é opensource. Se tiver interesse, segue meu blog: http://www.eversonnovka.com

    []‘s

  4. Responder DataSnap 2010 – enviando e recebendo ARRAY de strings, numbers e outros tipos | Andreano Lanusse Blog says:

    [...] sequência ao tema transferência de objetos com DataSnap o qual iniciei escrevendo sobre a transferência de um simples objeto, e depois sobre o envio de array objetos, agora vamos descrever como enviar array que contenha [...]

  5. Responder Marcio Costa says:

    Caro Andreano,

    Ótimo post parabéns.

    Uma pequena dúvida: Há algo pronto, no delphi 2010, para enviar/receber objetos mais complexos como por exemplo um TClientDataSet?
    Obrigado.

  6. Responder Bruno says:

    Muito bom o artigo, estou querendo fazer algo parecido com um Browser, onde todos os meus formulários ficariam do lado do Servidor e eu teria no lado Cliente somente uma carcaça para ler esses objetos do Servidor e traduzir. Acho que isso é possível usando o JSON, vou pesquisar mais, de qq forma obrigado.

  7. Responder Rafael Soares says:

    Boa tarde,
    Teria algum exemplo para a conversão genérica de objetos para JSON?
    Escrever dois métodos para para cada classe não me parece uma boa coisa. A conversão genérica de um objeto para JSON eu consegui, agora de JSON para um objeto está difícil…

  8. Responder Andreano Lanusse says:

    Rafael, agora não tem um método genérico, mas você pode criar um utilizando generics :)

    Para as próximas versões isso será transparente, mas você também terá a opção de controlar como converter.

  9. Responder Utilizando generics para transformação genérica de Objetos em DataSnap 2010 | Andreano Lanusse Blog says:

    [...] meu post anterior “DataSnap 2010 – Enviando e Recebendo objetos” mostrei como transferir objetos através de JSON objects, nos comentários relacionados a este post [...]

  10. Responder Andreano Lanusse says:

    Rafael acabei de publicar um post mostrando como fazer a conversão genérica.

    Obrigado pelo comentário.

  11. Responder Rafael Soares says:

    Tinha feito algo para parecido, também usando uma classe-base para herdar meus objetos, mas com generics ficou bem mais limpo.

    Obrigado

  12. Responder Eduardo Freire says:

    Andreano.
    Alguma consideração sobre a pergunto do Márcio Costa? Eu gostaria de tranferir objetos TClientDataSet ou TSQLQuery!

  13. Responder Andreano Lanusse says:

    Oi Eduardo,

    Na minha opinião não faz sentido, querer transferir TClientDataSet é a mesma coisa que transferir dados e isso ele já faz com o Provider, no caso de TSQLQuery é querer passar SQL isso você faz pelo ClientDataSet, server method ou outra forma.

  14. Responder José Abílio says:

    Adreano,
    Novamente lhe dando os parabéns pelo ótimo post, mas estou uma dúvida, terei que ter as classes tanto na aplicação cliente quanto na aplicação servidora?
    Isso não seria um retrabalho?
    Ter que refazer toda a estrutura de classes novamente ou no cliente ou no servidor.
    Por exemplo, aqui tenho uma série de classes com toda as regras de negócios e mapeamento objeto relacional, vou ter que fazer isso tudo denovo no servidor, ou tem algum jeito de fazer as regras de negócio no servidor com as classes que já tenho e no cliente apenas chamar elas, de algum modo sem ter que reescrever boa partes delas?

  15. Responder Juliano says:

    Ola Andreano.
    Primeiramente parabens pelo blog, muito bom msm.

    Seguinte fiz uma implementacao neste genero utilizando as dicas do outro artigo pra deixar a conversao generica, mas estou com uma dúvida.

    Como fica o gerenciamento da memoria no server, exemplo: Eu faco uma requisicao de uma lista, é feita a consulta instancia um JSonArray seta e devolve para a interface, mas a memoria ocupada por esta lista no server continua lah.

    Tem alguma dica.

    Mais uma vez parabéns.

    • Responder Andreano Lanusse says:

      Oi Juliano, obrigado.

      Fica lá até você destruir o objeto do server, uma vez passado para o cliente é outra instância.

  16. Responder Juliano says:

    Certo, mas como faço para destruir os objetos do server, visto que só poderei destruir eles apos a conclusão da solicitação no entanto quando a solicitação é concluída nao tenho mais acesso as objetos instanciado, já que a execução retornou para o cliente.

    Abraço

  17. Responder Silvio Mendes says:

    Muito bom mesmo esse post sobre datasnap, ainda estou me iniciando nisso mas ele demonstra o poder e a simplicidade de uso. Outro ponto é o uso do JSON, que já conhecia, mas no EXTJS que é todo baseado nessa notação.

    Com toda certeza terei perguntas, mas vou explorar mais os códigos aqui.

    Parabéns pelas dicas.

  18. Responder Transferência de objetos no DataSnap 2010 | Wecsley Fey.com says:

    [...] http://www.andreanolanusse.com/pt/datasnap-2010-enviando-e-recebendo-objetos This entry was posted on Thursday, July 15th, 2010 at 11:34 pm. You can follow any responses to this entry through the RSS 2.0 feed. Responses are currently closed, but you can trackback from your own site. [...]

  19. Responder Flávio says:

    Olá Parabéns pelo Artigo,
    Como eu testo o retorno deste desta aplicação servidora via http??

  20. Responder Paulo says:

    Exemplo fantastico do uso do DATASNAP, me ajudou muito na migração de uma sistema feio em delphi 2009.

    mas gostaria de saber como enviar e receber dados de um campo BLOB do banco de dados, eu até recebo mas nao consigo enviar. o sistema sempre reclama falando que o JSON nao suporta ARRAY e nem DATA.

    poderia passar um exemplo de como trabalhar com eses tipo de Dado usando o JSON e D2010 ?

    obrigado

  21. Responder Cleyton says:

    Olá Andreano, primeiramente otimo post, muito valido para mim.

    Eu gostaria de saber se é possivel fazer o inverso enviar um JSON para o Servidor, usando REST, estou iniciando em REST, ta ficando interessando, só que hoje tenho a necessidade de retornar um Objeto para o Servidor, e até o momento só descobri como passar os parametros e no formato String … por exemplo …

    http://127.0.0.1:8081/datasnap/rest/TSMTeste/GetTeste/AquiOParametro

    no resto mais uma vez parabéns, não somente por esse post, e também pelos outros.

    Obrigado.

  22. Responder Cleiton says:

    Andreano,

    parabéns pelo blog, sem dúvida alguma essas curtas postagem estão trazendo grandes resultados…hehehe
    Assim quanto a isso eu só tenho a agradecer, pois é graças aos posts como este que nós programadores podemos estar aprendendo, nos atualizando e etc…

    Bom, baseado neste teu tópico, eu fui tentar criar um exemplo, simples, claro, mas eu fiz mais para aprender. Eu criei um sistema de classes para fazer vendas/controle de estoque. minha idéia, o cliente quando quer fazer uma venda, ele chama uma função no servidor, e passa uma classe (TVenda) com as informações para o servidor proceder. Desse jeito eu consigo ter um controle de estoque bem consciente (controlando a concorrência…) bom mas o problema, foi que os produtos eu representei com uma classe TProduto, e a classe TVenda possuia uma TList , algo digamos, bem intuitivo…mas, na conversão de objetos JSON, essa lista, literalmente não converte. Eu não consegui encontrar alguma solução, por acaso você teria alguma idéia a respeito disso???

    Muito obrigado, pela atenção…

  23. Responder otto says:

    Tive o mesmo problema transportando propriedades do tipo Data, DateTime. Alguma sugestão?

  24. Responder otto says:

    fui realizar alguns testes criando objeto descendendo de TJSONObject, so que o mesmo é uma classe selada. Minha versão esta desatualizada?

  25. Responder Marcelo says:

    Boa tarde Andreano

    Estou tendo o mesmo problema que o otto mencionou ao transportar um objeto que possui uma property do tipo double.

    Poderia me dar alguma dica de como resolver esse problema?

  26. Responder Marcelo says:

    Andreano

    Obrigado pela resposta utilizo o Delphi 2010 apesar de não ser indicado a mudança nos fontes da vcl resolvi o problema seguindo o exemplo desse poste http://www.expressolivre.net/openmail/index.php?msg_id=%22123336%22 e funcionol perfeitamente.

    Agora estou com problema ao rodar a aplicação servidora em uma máquina com windows server 2003 sem farewall, testei em outras máquinas e funciona, na verdade não sei se a falta do firewall é o problema, mas, é o que difere das outras máquinas que testei.

  27. Responder Alexandre José says:

    Olá Andreano,

    Estou com a necessidade de transpostar o ClientDataSet como objeto para trabalhar no meu servidor de aplicação.
    É possível através de JSON? A princípio tenho erro de RTTI.

    Obrigado!

  28. Responder Alexandre José says:

    No meu caso gostaria de commitar vários CDS dentro de uma mesma transação, passando vários clients em um JSONArray. Irei tentar fazer isso via DBXReader. Eu utilizo isso com RemObjects, queria converter para o novo Datasnap. =)

    Obrigado!

    • Responder Andreano Lanusse says:

      Oi Alexandre, você pode ter uma única transação ao fazer o applyupdates de vários ClientDataSet se eles tiverem conectados, da uma olhada em nested clientdataset

  29. Responder Wesley says:

    Parabéns Andreano….

  30. Responder Dannyrooh says:

    Boa tarde,

    Criei um servidor datasnap que retorna uma lista de TCustomer agrupada com JsonArray e JsonValue, estou tentando consumir o resultado numa aplicação asp.net com delphi prism, ao gerar o proxy ele retorna a classe como object, alguma forma de realizar a transformação direto com .net ?

  31. Responder Rodrigo says:

    Excelente post, me ajudou muito, porém tenho um problema, já citado acima. Criei uma classe que possui property do tipo Double e me ocorre um erro na conversão do objeto, impossibilitando a transferência do objeto para o cliente. Como posso resolver o problema ?

    Att,

  32. Responder Francis Silva says:

    Eu consegui resolver o problema de transporte de datas e doubles entre o servidor DataSnap e a aplicação cliente utilizando um truque muito simples. Se você observar a estrutura de uma classe qualquer em formato JSON vai notar que o que é mapeado para o JSON não são as propriedades da classe em sí, mas sim as suas variáveis privadas. Sendo assim consegui resolver o problema som o seguinte truque:

    TCliente = Class (TObject)
    private
    FID: Integer;
    FNome: String;
    FDataCadastro: String;
    FValor: String;
    function GetDataCadastro: TDateTime;
    procedure SetDataCadastro(value: TDateTime);
    function GetValor: Double;
    procedure SetValor(value: Double);
    ….

    public
    property DataCadastro: TDateTime read GetDataCadastro write SetDataCadastro;
    property Valor: Double read GetValor write SetValor;
    ….
    end;

    O truque é na implementação dos métodos privados:

    function TCliente.GetDataCadastro: TDateTime;
    begin
    Result := StrToDateTime(FDataCadastro); // Vai bem alguma checagem extra aqui antes da conversão
    end;

    function TCliente.SetDataCadastro(value: TDateTime);
    begin
    FDataCadastro:= FormatDateTime(‘DD/MM/YYYY HH:NN:SS’, Value);
    end;

    function TCliente.GetValor: Double;
    begin
    Result := StrToFloatDef(FValor,0);
    end;

    function TCliente.SetValor(value: Double);
    begin
    FValor := FloatToStr(value);
    end;

    Dessa forma quando você atribuir ou obter um valor das propriedades DataCadastro e Valor, automaticamente eles serão convertidos de TDateTime e Double para String, e virce-versa. Como o JSON só armazena as informações dos campos privados das propriedades, as informações são armazenas como String e não há nenhum problema na conversão de volta na aplicação cliente.

    Espero ter ajudado.

  33. Responder Braga says:

    Olá Sr. Andreano Lanusse! Parabéns pela execelência de seu trabalho. Embora tenha procurado em várias fontes, não encontrei nenhum material editado sobre “Como construir uma aplicação do começo ao fim” com DataSnap, em 3 camandas.
    Se poder me ajudar com qualquer informação de onde e como encontrar, serei imensamente grato.

  34. Responder Nelson Lima says:

    Prezado Andreano,

    Eu gostaria de criar metodo remoto onde eu possa passar um array de Delta do ClientDataSet + seu ProviderName

    Para isso criei um class TDeltaApply Tentei TDeltaApplyArray : array of TDeltaApply e ele não aceita como metodo remoto esse tipo.

    Então como posso para meu servidor uma array de delta e seu providername????

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

    Boa noite Andreano!

    Estava estudando esse seu exemplo de transferência de objetos do servidor para o cliente e surgiu uma dúvida: Utilizando esse seu exemplo da classe TCustomer, poderíamos ter uma propriedade public do tipo TJPEGImage ou TBitmap, algo como TCustomer.Photo?

    Meu servidor iria definir o conteúdo dessa propriedade e passar o objeto via JSON para o cliente e o mesmo conseguir exibir em um TImage padrão, a imagem que está na propriedade Photo?

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

    Sobre o post acima… percebi que o problema é na conversão de JSON para Object, utilizando o método JSONToObject.

    Antes da conversão para JSON, um TImage consegue exibir a foto tranquilamente.
    Na volta de JSON para o objeto TCustomer, ao que parece, o conteúdo de Photo fica comprometido.

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

    Caro Andreano!

    Tentei realizar o teste que vc indicou, usando TStream para enviar a imagem para o cliente… Na aplicação servidor, a imagem é lida do Stream com sucesso mas, quando é enviado para o cliente, dá erro!

    O post foi detalhado para a nova situação… grato pela sua ajuda!

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

    Andreano!

    Consegui resolver o problema trocando a classe TMemoryStream por uma TStringStream.
    Mas, e quando não for possível fazer um processo como esse? E todo o projeto DataSnap já pronto parado por conta de um único tipo?

  39. Responder William says:

    Testem direito esse exemplo. O método toString que ele chama é da classe tcustomer que foi compilada dentro do executável do cliente através da declaração no uses, em nenhum momento foi executado o tostring do servidor datasnap.

    Só alterar o método tostring do tcustomer assim:

    function TCustomer.ToString: string;
    begin
    Result := Self.Name + ‘ – Age: ‘ + IntToStr(Self.Age)+’ teste’;
    end;

    e compilar o server e não compilar o cliente, vai ver que o retorno será sem a string ‘teste’ que foi colocado no método.

    • Responder Andreano Lanusse says:

      @William,

      Infelizmente você não entendeu o exemplo, o qual mostra o envio e recebimento de objetos no DataSnap.

      TCustomer é o objeto usado como exemplo, e no caso ele é usado no server e client. Para representar e ter acesso ao TCustomer no cliente você TEM que ter a estrutura do mesmo no cliente.

      O método ToString somente acessa a propriedade do objeto e não faz referência nenhum ao server.

Deixe uma resposta

O seu endereço de email não será publicado Campos obrigatórios são marcados *

*

Você pode usar estas tags e atributos de HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>