Novembro 2007 - Posts

Impersonate numa aplicação Win32

Habitualmente desenvolvo com ambiente Web e o Impersonate é pratica corrente para fugirmos ao HOP HELL. Nunca tinha deparando com um requisito que levasse a impersonalização de um processo para aceder a um recurso da rede.

Felizmente não foi difícil encontrar informação sobre tal assunto. O complicado é entender  como isto que é feito. Não existem métodos directos para fazer o Logon de um utilizador, pelo que, temos que usar o famoso DLLImport para importar o método da livraria advapi32.dll.

Para mais informações podem ver o seguinte artigo no Code Project - Windows Impersonation using C#.


Abraço
Paulo Aboim Pinto

Posted por Paulo Aboim Pinto with no comments
Filed under:

Abrir um ficheiro Excel com .NET

Desde os meus tempos do Visual Basic que abro ficheiros Excel e Word sem problemas, tanto para lá colocar dados como ler dados. Desta vez abrir um ficheiro de Excel foi uma aventura. Sempre que fazia o Open do Workbook obtinha o erro:

 old format or invalid type library. (Exception from HRESULT : 0x80028018 (TYPE_E_INVDATAREAD))

O mais estranho é que se a path do ficheiro estivesse errada, obtinha a mesma mensagem de erro....... estranho mesmo.

Depois de umas procuras com o Google, encontrei este link que tenta explicar minimamente o que acontece e como devo fazer. Não estou de acordo com a razão do erro, pois, o sistema deveria ser um pouco mais inteligente para saber o valor do CultureInfo a usar. Seja como for aqui está a solução de como abrir um ficheiro já existente.

System.Threading.

Thread thisThread = System.Threading.Thread.CurrentThread;
System.Globalization.
CultureInfo originalCulture = thisThread.CurrentCulture;

ApplicationClass _excelApplication = new ApplicationClass();
thisThread.CurrentCulture =
new System.Globalization.CultureInfo("en-US");
Workbook _excelWorkBook = _excelApplication.Workbooks.Open(@"FicheiroExcelDeTeste.xls", 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "", true, false, 0, false, true, false);

thisThread.CurrentCulture = originalCulture;

Posted por Paulo Aboim Pinto with no comments
Filed under:

"Fazer um SELECT que retorne 10 registos a uma tabela de 10 registos ou 10.000.000 de registos é a mesma coisa"

Estamos a falar de uma base de dados SQLServer e ainda bem que existe pessoas que sabem estas coisas.

Felizmente ainda foi dito: "É capaz de ser diferente, mas, são milisegundos!".

Abraços

CORRECÇÃO
Bem, enganei-me na frase. Agora está correcta.

Posted por Paulo Aboim Pinto with 6 comment(s)
Filed under:

Afinal à empresas em Portugal a pensar em desenvolver aplicações com Mono

Ontem fui a uma Reunião de Qualificação que visa a minha integração noutro projecto num cliente que trabalha com telecomunicações. Nestas reuniões pedem-me sempre para falar da minha experiência profissional e eu, para além de mencionar que trabalho com tecnologias Windows desde 1996, ultimamente tenho dedicado muito tempo a ajudar a comunidade Mono / Linux com testes ao MonoDevelop e sugestões de evoluções do produto.

Pela primeira vez a referência ao Mono foi bem aceite pelo cliente, pois, pelo que parece é do interesse do cliente em alguns layers da sua estrutura manter máquinas UX devido à fiabilidade, escalabilidade e durabilidade, mas, manter aplicações em C/C++ que correm nessas máquinas é penoso. Logo a ideia era instalar o Mono nessas máquinas usar Console Applications desenvolvidas em C# que corram da mesma forma em Windows como em ambientes UX.

Ninguém imagima como fiquei contente de ouvir isto. Finalmente alguém vê se a portabilidade de código é fundamental nos dias de hoje, não só, em termos de escolha do SO como em termos de homogenização dos recursos e da utilização das linguagens utilizadas no projecto.

Espero que o cliente tenha gostado da mais valia que posso trazer ao projecto deles, pois, fiquei entusiasmado em trabalhar com eles.

Abraços
Paulo Aboim Pinto

Posted por Paulo Aboim Pinto with 2 comment(s)
Filed under:

Esta agora???

Afinal não podemos perguntar ao sistema qual o formato que um ficheiro de texto foi gravado (ASCII, UTF8, ANSI, UNICODE, etc)?

Hoje tive que manipular um ficheiro de texto que vem do cliente e pensei para mim, abro normalmente e pronto. Não indiquei qual o formato no comando StreamReader. Eis que sempre que aparecia um caracter especial, este desaparecia e nem dizia "água-vai nem água-vem".

Estranho para um sistema que e gaba por ser o mais avançado e tal. Investiguei um pouco e descobri que quando não digo nada, o ficheiro é aberto em UTF-8 e que o meu ficheiro estava gravado em ANSI (Lembrem-se que este é o formato do Windows). Só abrindo o ficheiro em ASCII é que consigo que pelo menos o carater seja substituido e não REMOVIDO POR MÁ FIGURA da minha linha, menos mal.

Tentei saber se o sistema me dizia, dando a path do ficheiro, qual o encoding que foi gravado e tudo o que encontrei foi água. Nada de Porta-Aviões. Para saber essa informação, depois de abrir o Stream, o que se deve fazer é converter para os diversos formatos e comparar o número de bytes com o ficheiro original. Se o número for igual....... EUREKA.. é esse o formato.

Começei a imaginar que essa conversão não pode ser pacífica e no pior dos casos poderia ter que fazer 4 vezes para encontrar o formato do ficheiro. Não é pacífica, pois, posso ter ficheiros texto com aproximadamente 20 Megas para importar para o meu sistema.

Ahhh e tal, e se usasses XML? Mutos de vós perguntam e bem! Eu não mando no ficheiro do cliente. Ele manda como quer e altera quando entende e por vezes nem diz nada. Nós é que sempre nos "lixamos" (com F) e trememos quando vamos importar os dados, pois, NUNCA... mas NUNCA funciona à primeira. Estamos sempre a pedir ao cliente para nos avisar das alterações e .......................

Uffffaaa que tarde fastidiosa a tentar entender o erro e ainda pior quando não podia resolver. Leia-se o ficheiro em ASCII, pelo menos não dá problemas.

 

Abraços
Paulo Aboim Pinto

Posted por Paulo Aboim Pinto with 2 comment(s)
Filed under:

Ainda bem que temos a Microsoft para nos patentear coisas importantes

Desta vez foi o "Adeus" no final das conversas. Digam-me se isto é realmente importante para uma empresa de software?

Ainda bem que a europa não aderiu a esta palhaçada. Qualquer dia aparece uma patente do respirar.

Podem ler aqui a patente.

{fonte: Conversas do Bruno e TechDirt}

Posted por Paulo Aboim Pinto with no comments
Filed under:

Estranha utilização da memória em conexão à base de dados

Viva

Tenho andado aqui numa luta feia com conexões à base de dados. Normalmente nas minhas aplicações tento sempre que por sessão uma conexão seja iniciada quando a aplicação arranque e quando esta fecha, fechamos a conexão. Em aplições Web, tenho adoptado sempre a política de em cada operação, conecta-se à base de dados e depois fecha, libertando assim os recursos.

Com a aplicação que estou a desenvolver, a qualquer momento uma conexão a uma base de dados pode ser criada, seja a um SQLServer, DBase, Access, AS400, etc. Desta forma estava sempre a fechar a conexão e voltar a abrir na operação seguinte. Infelizmente este processo não está a funcionar da melhor forma, pois, sempre que abro uma conexão, gasto uma determinada memória, mas, se fecho a conexão, a mesma quantidade de memória não é libertada, isto é, liberta menos memória que a que aloca quando abre.

Isto pode ter origem em diversos factores, pois, durante a vida da conexão tenho operações de SELECT e INSERT que também usam memória. Mesmo assim, quando fecho a conexão, não deveria libertar todos estes recursos? Mesmo usando os métodos do System.GC, não consigo que a memória fique disponível.

Desta forma resolvi implementar uma Poll de conexões, isto é, tenho uma lista de todas as conexões já abertas e invés de criar sempre uma nova conexão, simplesmente uso um objecto que já existe, mas, o problema dos Open e Close mantém-se. Não posso fechar as conexões, se não corro o risco desta aplicação "comer" toda a memória disponível.

Assim sendo tenho uma poll de conexões ABERTAS as várias base de dados que este componente de integração se conecta. Claro que está situação não está bem resolvida, mas, infelizmente tou sem ideias. Mal seja iluminado, colocarei aqui a solução.

 

Abraços
Paulo Aboim Pinto

Posted por Paulo Aboim Pinto with 6 comment(s)
Filed under:

System resource exceeded.

Sim senhor, aqui está um erro no Jet Engine que diz tudo. Apesar do erro estar a ser retornado sempre que tento efectuar uma operação na base de dados, um

System.GC.WaitForPendingFinalizers();

no lugar certo resolveu o problema. Aparentemente havia conexões que ficavam abertas e mesmo igualando o objecto a NULL, a memória não era logo limpa. Com este comando obrigo a esperar pelo GC para limpar todos os objectos pendentes.

E assim perdeu-se um dia de trabalho, pois este erro só surgia quando decorridos 30m a 40m de um processo que iria demorar largas horas.

Eu perdi esse tempo, espero que voces não percam o mesmo tempo...

 

Abraços
Paulo Aboim Pinto

Posted por Paulo Aboim Pinto with 6 comment(s)
Filed under:

Poupar trabalho na ligação de um WebForm com uma(s) tabela(s) da base de dados

Estas últimas semanas tenho parado para pensar numa forma simples de persistir os dados de uma (ou várias) tabelas num único formulário.

 

Este é o funcionamento típico de uma aplicação Web, onde os dados da base de dados estão estritamente ligados à forma como são pedidos ao utilizador.

 

Como ultimamente tenho usado e abusado da metodologia MVP (Model View Presenter, uma evolução do MVC – Model View Controler) claro que esta foi a primeira abordagem usada. Felizmente penso ter encontrado a solução que procuro.

 

Antes demais quero definir alguns pressupostos:

  • Utilização de  3 camadas; Apresentação, Negócio e Acesso a dados, e um objecto comum a todos as camadas, Modelo onde está representadas as tabelas / views das base de dados.
  • Entre as diversas camadas comunicam sempre usando os objectos contidos no objectos de Modelo (ou Listas de objectos) e nunca objectos IDataReader, DataTable ou DataSet.

 

Desta forma, temos um exemplo de uma tabela com os campos ID (int)  e Nome (string). No objecto Model temos uma interface (ITableModel) que define o esqueleto desta tabela e uma class que implementa este interface. Assim temos um objecto que irá persistir os dados de cada registo da tabela.

Na minha camada de apresentação (usando o MVP) iremos ter uma interface que irá definir os campos que o utilizador manipula e se temos um formulário que manipula a tabela anteriormente definida, temos uma interface IDefault que implementa a interface ITableModel. Desta forma temos todos os campos da tabela definido no WebForm.

Derivo o meu formulário Default.aspx.cs do IDefault e atribuo os campos TextBox às variáveis definidas pela camada de apresentação.

Quando o utilizador pressionar no botão de Gravar, o WebForm passa para a apresentação os dados das TextBox e partir deste ponto posso fazer o cast:

ITableModel = (ITableModel) IDefault

Assim, tenho os dados a serem gravados na base de dados pela camada de acesso a dados num objecto, sem ter feito atribuições entre os campos e um objecto, etc.

Agora tenho que passar o objecto do tipo ITableModel para a camada de negócios e posteriormente para a camada de acesso a dados para criar as linhas de comando SQL.

Neste ponto podemos fazer de duas formas:

  • Criamos as linhas de comando SQL hard coded
  • Criamos as linhas de comando SQL usando Refletion

 

Se houver interessados poderei explicar como gero as linhas de comando SQL usando Refletion, o que me poupa imenso trabalho a fazer debug de SQL.

 

Aqui tem o projecto em VS2005 para poderem olhar.

Para terminar, o exemplo que coloco tem ainda a possibilidade de um WebForm persitir os dados de várias tabelas.

 

Abraços
Paulo Aboim Pinto

?>

Posted por Paulo Aboim Pinto with 2 comment(s)
Filed under: