Artigo Clube Delphi 86 - SOAP - Aprenda técnicas avançadas em um exemplo passo a passo- Parte 2
Nesta edição, veremos gerenciamento de sessão, envio de arquivos via SOAP, compactação e muito mais.
Na primeira parte deste artigo, começamos a construir nosso disco virtual, um aplicativo onde o usuário poderá enviar arquivos para um servidor remoto, listá-los e recuperá-los posteriormente. Criamos a interface gráfica do cliente, vimos um pouco sobre autenticação com SOAP, exceções remotas, envio e recebimento de SOAP Headers e como rastrear as chamadas ao servidor. Nesta edição, veremos gerenciamento de sessão, envio de arquivos via SOAP, compactação e muito mais.
Gerenciamento de sessão
O mecanismo de autenticação que implementamos funciona, mas não está completo. Ele retorna sempre o mesmo identificador de sessão, definido de forma hard-coded no código do servidor, o que não é, obviamente, uma solução segura. Precisamos gerar um valor que seja único entre todos os usuários que podem vir a se autenticar.
Aqui temos um problema: Web Service são por natureza stateless, o que significa que nenhuma informação é persistida entre as requisições processadas. Mas o servidor precisa “lembrar” dos identificadores gerados, para poder comparar com os fornecidos pelos clientes. Como conseguir isso? Uma alternativa é controlar sessões.
A implementação do protocolo SOAP disponível com o Delphi não fornece nenhum mecanismo de persistência nativo. Dessa forma, precisamos criar um. Atente então para um detalhe importante: nosso Web Service reside em uma DLL ISAPI, que é carregada pelo IIS na primeira requisição recebida pelo servidor.
Essa DLL fica no contexto do processo DLLHost.exe, também conhecido como COM Surrogate. E ela ficará lá, em memória, até ser descarregada, como você fez algumas vezes ao longo desse artigo. Mas Web Service não são statesless?
Sim, são! Abra novamente uDiscoVirtualImpl e observe a classe TDiscoVirtual. Esse é o nosso Web Service. É essa classe que é criada e destruída automaticamente a cada execução remota. O resto da unit permanece intacto, carregado na memória. Confuso? Vamos implementar para você entender melhor.
Selecione o projeto do servidor e adicione a ele um Data Module. Chame-o de “TdmSession” e salve o arquivo com o nome “uSessionDataModule”. Clique agora no menu Project e escolha View Source. Remova a seguinte linha de código: Application.CreateForm(tdmSession, dmSession);
Fizemos isso porque criaremos manualmente o Data Module. Adicione um ClientDataSet. Dê um duplo clique sobre ele para abrir o editor de campos e insira os seguintes Fields:
- SessionID: Tipo String, tamanho 38;
- LastAccess: Tipo DateTime;
- UserName: Tipo String, tamanho 10;
- UserID: Tipo Integer.
Clique de direita sobre o ClientDataSet e escolha Create DataSet. Pronto, já temos um DataSet para armazenar os identificadores de sessão gerados para cada usuário. Vamos então criar alguns métodos para gerenciar sessões. Adicione as linhas da Listagem 1 na seção public da classe TdmSessions:
function NewSession(const UserID: Integer;
UserName: string): string;
procedure RemoveSession(const SessionID: string);
function IsValidSession(
const SessionID: string): Boolean;
function GetUserID(const SessionID: string): Integer;
procedure UpdateLastAccess(const SessionID: string);
Implemente agora todos esses métodos (Ctrl+Shift+C) com o código da Listagem 2.
function TdmSessions.NewSession(const UserID: Integer;
UserName: string): string;
var
SessionID: TGUID;
begin
CriticalSection.Enter;
try
if not cdsSessions.Active then
cdsSessions.Open;
CreateGUID(SessionID);
Result := GuidToString(SessionID);
cdsSessions.Insert;
cdsSessionsSessionID.AsString := Result;
cdsSessionsStartDateTime.AsDateTime := Now;
cdsSessionsLastAccess.AsDateTime := Now;
cdsSessionsUserName.AsString := UserName;
cdsSessionsUserID.AsInteger := UserID;
cdsSessions.Post;
finally
CriticalSection.Leave;
end;
end;
function TdmSessions.IsValidSession(
const SessionID: string): Boolean;
begin
CriticalSection.Enter;
try
Result := cdsSessions.Locate('SessionID',
SessionID, []);
if Result then
Result := MinutesBetween(
cdsSessionsLastAccess.AsDateTime, Now) < 1;
finally
CriticalSection.Leave;
end;
end;
function TdmSessions.GetUserID(
const SessionID: string): Integer;
begin
CriticalSection.Enter;
try
Result := 0;
if IsValidSession(SessionID) then
Result := cdsSessionsUserID.AsInteger;
finally
CriticalSection.Leave;
end;
end;
procedure TdmSessions.RemoveSession(
const SessionID: string);
begin
CriticalSection.Enter;
try
if IsValidSession(SessionID) then
cdsSessions.Delete;
finally
CriticalSection.Leave;
end;
end;
procedure TdmSessions.UpdateLastAccess(
const SessionID: string);
begin
CriticalSection.Enter;
try
if IsValidSession(SessionID) then
begin
cdsSessions.Edit;
cdsSessionsLastAccess.AsDateTime := Now;
cdsSessions.Post;
end;
finally
CriticalSection.Leave;
end;
end;
Esses métodos servem para:
- Criar um novo registro no ClientDataset de sessões, retornando um identificador único (NewSession);
- Remover uma sessão do DataSet (" [...] continue lendo...
Artigos relacionados
-
Artigo
-
Artigo
-
Artigo
-
Artigo
-
Artigo