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.
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}
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.
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.
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!
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?
Com relação ao post anterior Andreano… a mensagem de erro é “Resource TServerMethodsFilial not found”
P.S.: A classe TServerMethodsFilial, herdando de TPersistent, é a classe que quero referenciar como ServerMethods em meu projeto…
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,
José, AV geralmente ocorre quando você está tentando acessar objetos que não foram criados.
O formato de concorrência vai depender do design de sua aplicação, esse artigo pode lhe ajudar http://www.andreanolanusse.com/pt/datasnap-compartilhando-conexao-com-o-banco-entre-diferentes-server-classes-a-partir-do-mesmo-cliente-session/
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?