Criando um contador de tempo de sessão em aplicativo web

Criando um contador de tempo de sessão em aplicativo web

Olá,

Realmente estou um pouco desapontado comigo mesmo, pois desde o último post se passou 3 anos… “Shame on you”… Mea culpa, minha vida mudou muito desde o último post, mudei de cidade, de emprego, enfim, nada justifica…

Voltando ao que interessa, gostaria de compartilhar com vocês uma solução bacana que utilizamos em um projeto que é o contador de tempo de sessão, bem parecido com aqueles cronômetros que existem em nossos internet bankings.

A solução basicamente é um mash up (uma mistura) de um User Controls e um objeto externo, ambos disponíveis no marketplace do GeneXus: Web.Config reader e SessionTime. A idéia é utilizar o user control Session Time, porém, ao invés de configurá-lo com um tempo fixo, obter o valor do tempo de sessão do web.config.

  1. A primeira coisa que precisa ser feita é o download e a instalação do U.C. e do objeto externo, caso necessite de ajuda nesse ponto, poderá encontrar a documentação aqui.
  2. O external object ConfigManager não necessita instalação, mas é necessário a importação dos objetos na sua KB, para isso, após efetuar o download, descompacte o arquivo webconfigreader.xpz para alguma pasta;
    • Vá no menu Knowledge Manager e selecione Import; Selecione o caminho onde foi posto o arquivo .xpz e selecione import.
    • Feito isso serão importados 1 External Object, 2 Files e 1 Webpanel de teste;
    • Se desejar, execute-a, para verificar se está tudo OK com o leitor de web.config:
    • Uma chave que pode ser lida sem problemas do web.config é a de nome DocumentType que por padrão está vindo com o valor HTML5.
  3. A seguir, necessitaremos incluir o user control em nossa masterpage, para que o mesmo fique sempre visível. eu recomendo adicioná-lo no cabeçalho da mesma: Sem títuloAo executar a aplicação podemos ver que agora existe um contador de sessão na masterpage:

    Sem título 2

    Também podemos notar 2 coisas:

    1. O tempo de sessão está sendo definido de forma manual, isso é, está sendo configurado diretamente no user control, ao invés de ser obtido do tempo de sessão real que o IIS nos oferece;
    2. O Layout está um pouco grande demais.
  4. Para corrigir o problema da integração com o IIS é que instalamos o external object Webconfig Reader, ele que será encarregado de obter o valor do tempo de sessão configurado na nossa aplicação. Para fazer isso, basta adicionar a seguinte linha no evento start da página onde está posicionado seu user control de tempo de sessão, no nosso caso, está na própria masterpage:
    ControlSessao1.Minutes = ConfigManager.getSessionStateTimeOut()
    
    Onde ControlSessao1 é o nome do controle utilizado na tela.
  5. Para ajustar o layout necessitaremos de um pouco de conhecimento em CSS, mas não é nada muito difícil: Todo user control é “renderizado” em tempo de execução, ou seja, no objeto gerado será feita uma referência ao código que deverá ser inserido no html, essa inserção será feita em tempo de execução. Logo, para alterar alguns detalhes do user control, basta editar o arquivo que está sendo referenciado, nesse caso se chama ControlSessaoRender.js e está na subpasta de nome ControlSessao, dentro da pasta Web de nossa aplicação.Uma maneira rápida é utilizar a configuração da fonte para que seja definida uma classe, ao invés do tipo de letra. Para isso, basta substituir a linha 40 do arquivo, onde diz:
    var buffer = '<a id="Sessao" href="#"><font face="' + this.FontFace + '" color="' +  this.FontColor + '" size="' + this.FontSize + '">'+ relogio + '</font></a>';

    por isso:

    var buffer = '<a id="Sessao" href="#"><font class="' + this.FontFace + '">'+ relogio + '</font></a>';

    O que estamos fazendo aqui é utilizando a propriedade FontFace do user control para que ao invés de configurar o tipo de letra, seja configurado a classe CSS a qual se deseja utilizar para esse texto.

    Também necessitaremos colocar o código a seguir, logo abaixo da linha que inserimos no evento start no item anterior:

    ControlSessao1.FontFace=ThemeClass:Label

    O que está acontecendo aqui é que estou dizendo que a fonte do controle de sessão agora receberá o nome da classe “Label”, notar que essa notação faz com que a classe passe a ter integridade referencial, ou seja, ao tentar remover a classe “Label” do meu objeto tema, ocorrerá um erro dizendo que ela está sendo referenciada. Nesse exemplo também poderia ser utilizado o código:

    ControlSessao1.FontFace="Label"

    Porém perderemos a integridade e caso essa classe fosse removida, nosso user control aparecerá desconfigurado.

    Assim, veremos agora como ficou nossa página:

    Sem título 3

  6. Como etapa opcional, complemento dizendo que ainda é possível melhorar um pouco mais, assim como no item anterior editamos somente a classe do texto, podemos editar o próprio texto, de forma que fique um pouco mais intuitivo, na linha 39 do mesmo arquivo ControlSessaoRender.js, temos o texto que está sendo utilizado:
    var relogio = this.tempo.getMinutes() + " Minutos : " + this.tempo.getSeconds() + " Segundos."

    Podemos, por exemplo, alterá-lo para:

    var relogio = “Tempo restante: “+ this.tempo.getMinutes() + ” min.  e ” + this.tempo.getSeconds() + ” seg.”

    O bacana é que a alteração do arquivo .JS é refletida automaticamente, basta recarregar a página que o texto aparece alterado.

    Finalmente, nossa página ficou assim:
    Sem título 4

 

Espero ter contribuído de alguma forma, qualquer dúvida ou problema que tiverem podem me deixar uma mensagem aqui embaixo, respondo ASAP.

Um abraço e até a próxima.

 

Acessando variáveis no web.config

Ola a todos.

Muito tempo se passou desde meu último post e peço desculpas, mas tudo na vida da gente acontece por alguma razão e desde minha última aparição muita coisa mudou, meu emprego, minha cidade atual, dentre outras, bueno, nada disso justifica eu sei, mas tive de repensar em um monte de coisas de um dia para o outro e acabei me esquecendo desse projeto, por isso as desculpas.

Recentemente estive trabalhando em um projeto realmente pequeno com apenas três tabelas no DBMS e fiquei me perguntando se realmente havia a necessidade de criar uma quarta tabela apenas para guardar parâmetros… Decidi que não, não queria.

Então lembrei que é comum no desenvolvimento tradicional (aka “a mão”) armazenar configurações de acesso rápido no arquivo web.config, então resolvi que iria fazer isso.

Tive alguns problemas quando tentei gravar valores no web.config utilizando a classe ConfigurationManager, depois fui descobrir que por motivos de segurança a gravação não foi implementada, o método para escrever até existe e ao ser executado não retorna erro, mas o web.config simplesmente não é atualizado. Fiquei um pouco confuso, mas depois analisando com calma vi que era uma sábia decisão… hehehehe

A solução foi mais simples que eu pensava, existe uma classe no C# que acessa diretamente a seção appSettings de dentro do web.config, a única coisa que faltava era criar o Wrapper, o External Object e utilizá-los.

O resultado final disso acabei utilizando como piloto para meu primeiro projeto no marketplace do GeneXus.

Resumindo, o que você precisa fazer é:

1 –  Baixar a extensão nessa URL: http://marketplace.genexus.com/product.aspx?web.config.reader
2 – Importar o arquivo “WebConfigReader.xpz” para a sua base de conhecimento;
3 – Certifique-se que o arquivo ConfigManager foi corretamente copiado para o diretório da aplicação <app>\bin; (Os arquivos ConfigManager.cs e ConfigManager.dll estão embutidos no .xpz);
4 – Efetue um build all;
5 – Execute a webpanel WebConfigReader para testar;

Obs.: Esse External Object foi criado utilizando GeneXus X Evolution 2 Upgrade 2, mas acredito que deva funcionar também na Evolution 1.

Sinta-se livre para utilizá-la onde achar melhor, e por favor, se precisar de ajuda não hesite em perguntar.

Se desejar, no .zip está o fonte e um .bat para auxiliar na compilação.

Abraços a todos e até a próxima.

Autenticando usuários de aplicações no Windows e SQL Server

Hola! Que tal? (Como dizem nossos amigos uruguaios)

Estive ausente já faz um bom tempo, e de fato iria continuar por mais algum tempo, mas recentemente (hoje, pra ser mais sincero) implantei um pequeno sistema que se autentica com usuários do domínio (AD) do windows diretamente no SQL Server.

Oras, mas pra que serve isso? Basta deixar um usuário fixo da aplicação no sql server e pronto! Realmente isso funciona 100% adrenalina (como diria meu amigo Nataniel…).

Sim funciona sim, mas suponha os seguintes cenários:

  1. Sua aplicação está consumindo grandes recursos de processamento;
  2. Você sabe que somente sua aplicação está utilizando o DBMS;
  3. Você gostaria de saber qual usuário está realizando a query “from hell”;
  4. Você gostaria de criar auditorias em algumas tabelas, via trigger;

Em algumas dessas situações, se você utiliza autenticação pelo SQL Server (e não pelo domínio, ou Active Directory), saber exatamente qual usuário pode ser um problema, visto que todas as conexões vindas do servidor de aplicação fazem login com o mesmo usuário do SQL Server.

Nesses casos (e também caso aquele dba esteja te solicitando) a aplicação pode se autenticar pelo domínio do windows, sem ter que fazer nenhuma alteração no GeneXus, somente alterando configurações do próprio IIS. Vamos a elas…

Pré-requisito opcional: Recomendo a instalação do IIS Admin Pack, que é um pacote que adiciona algumas funcionalidades bacanas ao IIS Manager, entre elas a possibilidade de se editar graficamante configurações do web.config que antes eram somente na raça (editando o web.config). Esse pacote pode ser baixado da própria MS: http://www.iis.net/download/AdministrationPack

As configurações abaixo foram testadas em aplicativos GX 9 e X evolution 1, com IIS7 rodando em windows 7 e em um servidor windows 2008;

  1. Configurar o pool do aplicativo para fazer autenticação pelo ASPNet: Selecionar o pool de aplicativos vinculado a sua aplicação, e clicar em configurações avançadas:
    Image
  2. Configurar sua aplicação para autenticação integrada: Editar o web.config, ou pelo Genexus, ou pelo editor de configurações do IIS, trocar “Integrated Security” de “no” para “yes”:
    Image
    e depois:
    Image
  3. Desabilitar a autenticação anônima, e habilitar a autenticação do windows e a personificação do ASPNET:
    Image
    e depois:
    Image
  4. e, finalmente, forçar o IIS a utilizar a autenticação do ASPNET, aqui se torna extremamente fácil se você instalou o Administrator Pack: Abrir o Editor de configurações, selecionar system.webServer/security/authentication/windowsAuthentication, e alterar o valor “useAppPoolCredentials” de “False” para “True”:
    Image
    e depois:
    Image

    Aqui na propriedade “providers” é interessante deixar apenas NTLM, basta clicar nos “…” e remover a opção “Negotiate”

Nesse último passo, se você não instalou o admin pack, terá que editar “a mão” o arquivo web.config para adicionar as sessões relativas a essas configurações, que eu não sei exatamente quais são;

E é isso, fazendo esses pequenos passos os dba’s agradecem! 🙂

P.S.: Não esqueçam de autorizar seu usuário do windows no SQL Server, ou então irá receber uma mensagem de erro, dizendo que seu usuário não pode fazer login na base de dados…

Um abraço, e até a próxima!
Sandro M. Vianna

Behind GeneXus ou Beyond GeneXus???

Se você está se perguntando: “Epa, peraí, acessei esse site ontem (ok, ok, semana passada) e ele estava aqui, mas não está mais???

Não é um erro não, mudei o nome e o endereço do site…

Antes era behindgenexus.wordpress.com

Agora é beyondgenexus.wordpress.com

Os Motivos? Bom, tenho alguns que com certeza não justificarão a latência com que os resultados do google irão se atualizar, nem justificarão as prováveis perdas de lugares nos algoritmos do google. Mas os fins justificam os meios… enfim, vamos a eles:

1) Já existia um site com o mesmo nome, porém em outro serviço de blog (behindgenexus.blogspot.com). É de um velho conhecido meu, Gastón Milano, que trabalha na ARTech (fabricante do Gx). Apesar de que, logo que criei o site e notei (buscando pelo google) que já existia o mesmo nome, questionei-o sobre seu possível aborrecimento, ou simples  “Não curti” (Aliás é algo que o facebook deveria implementar…), em Porto Alegrês seria algo como “Não era”.
Bom, o que importa é que esse fato estava ME aborrecendo um pouco, primeiro porque não gosto de tomar créditos pelo trabalho de ninguém, por NADA de ninguém, se faço algo é para ser bem feito e que siga meus princípios… ou seja, talvez eu não tivesse gostado se EU tivesse um blog e outra pessoa criasse um blog com o MESMO nome e que trate do MESMO assunto…

2) O nome “behind” inconscientemente me leva ao tema “por trás”, “coisa ruim”, “traição”, hehehe, to zoando, mas me remete ao tema “Bom, irei abordar tudo que o GeneXus não aborda.” onde na verdade o que eu queria dizer era “Bom, irei abordar tudo o que o GeneXus aborda e MAIS um pouco”, coisas que vão além do GeneXus, coisas que o genexus faz OU que não faz.

Basicamente são esses 2 motivos, mas aí você se pergunta: “Ta seu idiota, mas porque tu não manteve os dois rodando e foi migrando aos poucos???”

Respondo-lhes: “Simplesmente porque… foi cagada mesmo… hehehe, tentei e tentei até que fiz um daqueles Next Next Finish de um assistente de exclusão do WordPress… até que ‘pluft…’ Odeu-se, como diria meu amigo Didi…”

Ai vai aposto que vai vir outro perguntando: “Ta, mas tú ficou 6 meses sem escrever nada e veio me fazer essa besteira? Quanto tu vai atualizar esse blog?”

Respondo-lhes: “Em breve… muito breve… Já está saindo do forno um tema com bastante desavenças: Stored Procedures em Oracle!” “Ok, não foi tão breve assim, nem foi esse o assunto…”

Recompilando (toda) a aplicação sem fazer Build All

Boa tarde!

Desculpem-me a demora mas antes tarde do que mais tarde, né?

Hoje quero falar um pouco sobre recompilação da aplicação, vamos lá… O Problema: Recentemente compilei uma aplicação *inteira* em .Net, só que utilizando o framework de 64 bits, e para piorar, utilizando a versão 4.0.

Como era uma versão de produção e alguns clientes podem não ter servidores 64 bits, resolvi então recompilar *toda* a aplicação novamente. Porém, se você for simplesmente no menu de execução do genexus (da versão 9.0 e anteriores, claro), selecionar o objeto e clicar “Compile” ou “Vai”, simplesmente não vai acontecer nada, pois o objeto *já* está compilado, certo?

E agora? Vou precisar fazer um Build All de mais de 5000 objetos (dos quais mais de 1000 são “main”) simplesmente para poder compilar em outra versão do Framework?

A resposta é não, você não precisa: O Genexus controla a necessidade de compilação através do timestamp do arquivo fonte, ou seja, se o timestamp do fonte for menor que o timestamp do arquivo compilado, não há necessidade de compilação. Ou seja, basta ter uma maneira de mudar o timestamp do(s) arquivo(s) fonte(s) necessário(s) para conseguirmos “marcar” determinados objetos como necessários (ou required na janela de compilação).

Para alcançar essa façanha, então, é necessário um utilitário chamado touch.exe ele está em qualquer diretório de modelo de aplicações geradas com java.

Copiar o utilitário para o diretório do modelo que você deseja “tocar”, aí então fazer o seguinte:

  1. Abra um prompt do DOS (Iniciar, executar, cmd.exe, ok);
  2. Posicione-se no drive e pasta do modelo onde foi estão os fontes a serem “tocados” (e onde deveria ter copiado o executável touch.exe). No meu caso foi:
    1. D:
    2. Cd \Modelos\KB20110727\DataNETSQLProducao
    3. touch hhome.cs
  3. Feito isso a webpanel home deverá aparecer novamente como “required” na lista de compilação, basta selecioná-la e clicar em “Agora Vai”, digo, “Compile”

Simples não?

Aposto que você deve estar se perguntando: “Tá, beleza, vou ter que fazer isso para cada um dos 1500 “mains” que tenho para serem recompilados?”

A resposta é novamente: “Não”: São poucas (acho) as pessoa que acompanharam a evolução do DOS, quem realmente acompanhou sabe que o Windows 95, 98 e o Millennium foram “construídos” em cima do DOS, ou seja, eles eram ambientes operacionais e não sistemas operacionais de fato (diferente da série NT: NT 3.5, NT 4.0, Windows 2000, Windows XP…). Bom estou lembrando isso pois o DOS continua por trás de *todas* essas versões, e um dos comandos DOS que pouca gente utiliza (ou conhece) é um pequeno comando de três letras chamado: FOR.

Esse comando faz exatamente o que faz nas linguagens de programação: Repetição… Repetição, 1499 mains a serem “tocados”… Parece ter algo a ver…

Pois bem, tem sim, e vamos a sintaxe  desse comando que resolve boa parte dos casos:

FOR <nome do conjunto> IN (<critérios de filtro>) DO <comando> [<nome do cojunto>]

Para o meu caso, executei (os nomes de conjuntos devem começar com ‘%’):

FOR %1 IN (*.cs) DO touch %1

Simples não? Também acho

Não achou simples? Tudo bem, você pode fazer o Build com Force Generation dos 1500 objetos mains que terá o mesmo resultado, só que vai levar um tempinho a mais… Só umas duas ou dez horinhas…

Um abraço, e até a próxima!

Manutenção de KB’s

Buenas!

Demorei mas voltei…

Hoje quero falar um pouco sobre as KB’s GeneXus (até a versão 9.0).

Todos os objetos GeneXus são armazenados em arquivos .dat, esses arquivos guardam todo tipo de informações relativas à sua KB em forma de tabela, por exemplo: Se tem uma tabela de modelos (Design, Protótipo, Produção1, 2, 3, etc.), objetos, atributos, cross references, etc. (Para mais informações sugiro pesquisar sobre o PublicGx – que brevemente falando, disponibiliza sua KB em forma de tabelas).

As KB’s GeneXus são armazenadas em arquivos, originados da tecnologia ISAM, isso é, são arquivos de dados juntamente arquivos de índices (semelhante ao nosso velho amigo DBF).

Isso implica que, as exclusões de registros são lógicas, ou seja, são marcados os registros como excluídos, porém eles não são de fato eliminados dos arquivos físicos.

Com o passar do tempo, pode acontecer das KB’s acumularem bastante registros nesse estado, o que, nesse caso, é aconselhável realizar um rebuild.

O que esse rebuild faz? Basicamente reescreve todos os arquivos .dat e .idx da sua KB ,eliminando as exclusões lógicas, resultando (não necessariamente) em arquivos menores, mais enxutos.

Outro grande benefício do rebuild é que ele reindexa todos os índices existentes (um para cada arquivo .dat). Fazendo com que objetos que não mais existam, sejam removidos do índice, por exemplo.

Ou, ainda, se você excluiu um modelo inteiro, porque não precisava mais dele (Sim, você pode excluir qualquer modelo da sua KB – exceto o Design, claro – Basta ir para o modelo de Design e clicar em File/Delete Model), é extremamente aconselhável que seja feito um rebuild para enxugar a sua KB, visto que a tabela que armazena os objetos tem como chave primária o número do modelo, ou seja, para cada modelo que você crie essa tabela é duplicada (em relação aos objetos) com o novo número do modelo gerado.

Bom, em primeiro lugar gostaria de salientar que antes de fazer qualquer um dos passos a seguir é recomendável um BackUp da KB! Não necessariamente TODA a KB, apenas os arquivos .dat e .idx que são os que serão alterados aqui.

Para fazer um rebuild (GeneXus 9.0):

  1. Fechar sua KB!
  2. Abrir um prompt do DOS:
    1. Iniciar, Executar, Cmd, [OK] .
  3. Posicionar-se no diretório da KB, ex.:
    1. d : [ENTER]
    2. cd \projetos\KB90\Minha_KB_90 [ENTER]
  4. Digitar “c:\Program Files\ARTech\GeneXus\GeneXus90\rbld” -y

Para fazer um rebuild (GeneXus 8.0):

  1. Fechar sua KB!
  2. Abrir um prompt do DOS.
  3. Posicionar-se no diretório da KB, ex.:
    1. d : [ENTER]
    2. cd \projetos\KB80\Minha_KB_GX80 [ENTER]
  4. Digitar “c:\Program Files\ARTech\GeneXus\Gxw80\rbld” -y

À partir do ponto 3 serão exibidos sucessivos ‘d’  e ‘i’ na tela, onde ‘d’ significa um arquivo .dat sendo reconstruído e ‘i’ significa um arquivo .idx sendo reconstruído.

Após a finalização, pode-se entrar normalmente na sua KB, mas guarde aquele BackUp até que se tenha conseguido abrir todos objetos sem problemas.

Nota 1: Se você tem a versão brasileira do windows, substituir “Program Files” por “Arquivos de Programas”.

Nota 2: Se você tem uma versão 64-bit do windows, substituir “Program Files” por “Program Files (x86)”.

Nota 3: Se a nota 1 e a nota 2 forem verdadeiras… Acho que não preciso dizer, certo?

Nota 4: Se você chegou até aqui esperando algo a mais, desista… o artigo já acabou…

Nota 5: Feliz Natal!.

Nota 6: Próspero Ano Novo!

Um abraço, e boas festas.

Lendo e gravando SDT’s em arquivos físicos

Buenas mi amigos!!!

Demorei um pouco, mas estou de volta para felicidade de alguns e infelicidade de nenhuns… hehehehe

Hoje queria falar rapidamente sobre SDT’s e XML’s

À partir da versão 8.0 do GeneXus, foi implementado o SDT (link para o release notes aqui)…

SDT? Super Dupper Tuppleware??? Simples Didático e Tal??? Não… nada disso… significa Structured Data Types, tipos de dados estruturados… Lembram do struct da linguagem C? Pois é, bem parecido, porém bem mais robusto e simples de ser utilizado.

Imagine um simples XML com a estrutura:

<Clientes>
<Cliente>
<Id>1</Id>
<Nome>Asdrubal </Nome>
<Telefone>3333-3131</Telefone>
</Cliente>
<Cliente>
<Id>2</Id>
<Nome>Pafúncio</Nome>
<Telefone>3332-3232</Telefone>
</Cliente>
</Clientes>

Até a versão 8.0 não se tinha como representar essa estrutura, em memóra, exceto com um vetor (ou matriz em casos um poucos mais complexos). O que tornava sua operação complicada…

Porém na versão 8.0 pode-se trabalhar com o conceito de SDT, ou seja uma variável (qualquer) estruturada da forma que quisermos.

Então, poderia-se representar essa estrutura através de duas variáveis SDT no genexus, porque duas? Simples, pois uma variável guardará a coleção de todos os clientes (no nosso exemplo só temos 2, mas poderiam-se ter vários…) e outra que será utilizada para navegar em cada item dessa coleção de clientes, simplificando, acessaria as propriedades ID, Nome e Telefone de cada cliente da coleção.

Temos então a variável &Clientes_Col, sendo do tipo de dados SDTClientes e a variável &Cliente_Item sendo do tipo de dados SDTClientes.Item (o nome item é configurável no momento da criação da SDT).

À partir daqui vou dividir em dois subtópicos (Gravando em um SDT e Lendo em um SDT).

  1. Gravando em um SDT. Diante das estruturas e das variáveis acima, seria fazer isso:
     //Adiciono estaticamente os valores a cada uma das propriedades
     &Cliente_Item.ID = 1
     &Cliente_Item.Nome = 'Asdrubal'
     &Cliente_Item.Telefone = '3333-3131'
     //Adiciono esse item dentro da minha coleção de clientes
     &Clientes_Col.Add(&Cliente_Item)
     //Instancio (ou crio) uma nova variável de clientes para o próximo item...
     //Notar que após o comando New, é utilizado uma string disponível no menu Inserir/Structured Data Type juntamente com '(' e ')'
     &Cliente_Item = New SDTClientes.Item()
     //Adiciono o segundo cliente, também estaticamente
     &Cliente_Item.ID = 2
     &Cliente_Item.Nome = 'Pafúncio'
     &Cliente_Item.Telefone = '3332-3232'
     //Existe uma alternativa que também funciona, e tem o mesmo efeito das linhas onde é adicionado o item à coleção e a criação de uma nova instância do item
     //(últimas duas linhas antes do segundo item) que é:
     &Clientes_Col.Add(&Cliente_Item.Clone())
    //Essa linha adiciona na coleção uma cópia do item &Cliente_Item
    //Porém costumo usar a primeira alternativa por tornar-se mais intuitiva para quem lê

    Pronto, isso bastaria para popular meu SDT com dois clientes, conforme a estrutura XML do início…

    Você pode estar se perguntando.. Peraí, eu instancio um novo item após a adição desse item à coleção??? E o primeiro item? onde foi instanciado…

    É amigo, lembre-se, estamos utilizando GeneXus e não uma linguagem tradicional… O primeiro item já está “instanciado”, porém sem valores, e é por esses motivo que não instanciei um novo item ao final da 2ª adição, pois não vou precisar de outro item, da mesma forma que se eu acessar, após todos esses comandos, a variável &Cliente_Item ainda vou ter o valor do último item, em memória, sim, essa é a grande diferença de se adicionar com o método Add(&Variavel) + New Item() e Add(&Variavel.Clone()) , ou seja, quando utiliza-se add(&item) + new é criada uma nova instância da variável de item, perdendo-se seus valores das propriedades atuais.

  2. Lendo em um SDT. Diante das estruturas gravadas acima, vou utilizar as mesmas variáveis somente para simplificação, com exceção das variáveis &Cliente_ID, &Cliente_Nome e &Cliente_Tel que utilizei somente para demontração:
    //A sintaxe é For Each <Item SDT> in <Coleção SDT>
    For Each &Cliente_Item in &Clientes_Col
        &Cliente_ID = &Cliente_Item.ID
        &Cliente_Nome = &Cliente_Item.Nome
        &Cliente_Tel = &Cliente_Item.Telefone
    EndFor

    A leitura é infinitamente mais simples que a gravação, certo?

    Como diria meu professor de Cálculo B: Daqui pra frente é trivial…

  3. Bacana, super supimpa, mais que demais… só que isso todos que trabalham com genexus já estão carecas de saber… certo???

    Porém a questão é… E se e quiser gravar esse SDT em um arquivo… e… lê-lo de um arquivo??

    A resposta é… Bom… O SDT não foi feito para isso, mas você pode fazer…

    É, mas os SDT’s não tem métodos para abrir e fechar, nem ler ou gravar em arquivo…

    A resposta é… Sim, eles não tem… mas para isso existem outros tipos de dados que trabalham com XML… XML Reader e XML Writer… Calma gente… é bem mais simples do que parece…

    Vou separar novamente em dois tópicos… Gravando um SDT em arquivo, e Lendo um SDT em Arquivo…

  4. Gravando um SDT em arquivo
    //Para esse tópico e para o próximo, utilizarei a variável &XML (Varchar de 100.000 posições)...
    //A variável &Writer é do tipo Xml Writer.
    //Carrego a variável &XML com o conteúdo do SDT (em forma de XML)
    &XML = &Clientes_Col.ToXml()
    //Abro o arquivo para escrita
    &Writer.Open('arquivo.xml')
    //Escrevo o conteúdo da variável &XML
    &Writer.WriteRawText(&XML)
    //Ou: &Writer.WriteRaeText(&Clientes_Col.ToXml())
    //Fecho o arquivo
    &Writer.Close()
  5. Lendo um SDT à partir de um arquivo
    //Para esse tópico utilizarei duass novas variáveis: uma chamada &Reader do tipo de dados XMLReader, e outra chamada &Erro, numérica de 2 posições.
    //Abro o arquivo .xml
    &Reader.Open('arquivo.xml')
    //Verifico se não aconteceu algum erro (arquivo inexistente, arquivo em uso, etc.)
    &Erro = &Reader.ErrCode
    
    If &Erro = 0 //zero
     	//Aqui sim, efetuo a leitura do arquivo inteiro para a variável &XML
    	&XML = &Reader.ReadRawXML()
    	//Populo o SDT à partir da variável &XML
    	&Clientes_Col.FromXML(&XML)
    	//Sim, eu poderia fazer os dois comandos em uma linha somente:
    	//&Clientes_Col.FromXml(&Reader.ReadRawXML())
    	//Por motivos de facilidade de entendimento utilizei uma variável auxiliar...
    	//Fecho o arquivo
    	&Reader.Close()
    Else
    	Msg("Ocorreu um erro ao abrir o arquivo.")
    Endif

Bom, espero ter contribuído mais um pouquinho…

Um abraço e até a próxima…