sexta-feira, 29 de novembro de 2013

Fazer uma consulta no SQL Server e enviar o resultado por e-mail, usando C#

Esse é um exemplo em C# que eu sempre passo para todo mundo que está começando na linguagem e quer aprender qualquer coisa um pouco mais complexa do que um "hello world".
Trata-se de um script / função que consulta um banco de dados e devolve o resultado, como um relatório, por e-mail. Então dois temas são abordados: conexão com o banco de dados consultando-o e envio de e-mail.
uso C# para me conectar com um banco de dados MS SQL Server e fazer uma query. O resultado da query é enviado por e-mail, como texto, no corpo do mesmo.
Originalmente escrevi esse programa como exemplo para um colega não programador, que já sabia programar um pouco, porém no VBA do Excel, e que já conhecia o Microsoft SQL Server muito bem e sabia fazer queries e trazê-las para uma planilha excel, mas não conhecia nada de C# e não tinha vivência como programador.

No entanto este tutorial também é destinado à webdesigners que precisam fazer um script para envio de e-mail, mas não querem se aprofundar no C#.

É um exemplo bem simples, e é mais simples ainda de se fazer no C#.

Se você precisar (com certeza vai) de algum relatório um pouco mais avançado que seja enviado por e-mail, pode fazer um script que consulte o banco de dados e devolva o resultado por e-mail, algo assim:






/*
    esqueleto básico de uma aplicação do tipo console 
*/


/*

	textos que devem ser trocados, de acordo com a situação:
	1)[[servidor]] Servidor do banco de dados MS SQL Server (host ou ip)
	2)[[banco_de_dados]] Nome do banco de dados
	3)[[login]] login do banco
	4)[[senha]] senha do banco
	5)[[tabela]] tabela, view ou procedure / sentença sql a ser executada
	6)[[campo 1]],[[campo n]] campos 1 ... n do resultado da consulta a serem trazidos no texto
	7)[[remetente]] remetente do e-mail
	8)[[destinatario]] destinatário do e-mail
	9)[[com copia]] com cópia para 
	10)[[servidor de e-mail]] Servidor de e-mail
	11)[[login do email]] login do e-mail
	12)[[senha do email]] senha do e-mail


*/

//essas estruturas depois da palavra using, do lado de fora da classe, chamam-se namespaces. 
//Cada namespace é uma subdivisão de uma hierarquia de bibliotecas de classes, que se encontram em um arquivo
//namespaces podem ser de sistema, que já vem junto, podem ser feitos por você, ou podem ser comprados
//using um.namespace significa que nesse arquivo sendo editado agora você usará recursos que estão nesse namespace. 

//a árvore completa de namespaces é tão grande que a microsoft tem um site onde você pode pesquisar, mais fácil do que colocar tudo num livro

using System; //este é o principal namespace, onde se encontram as funções básicas do sistema. Este é obrigatório.
using System.Collections.Generic; //este namespace serve para lider com coleções genéricas em memória. Não será usado aqui, e é desnecessário, mas o visual studio coloca automaticamente.
using System.Linq; //este namespace serve para fazer consultas "tipo sql" via C#, em coleções de memória. Pode ser usado com bancos de dados, mas não o usaremos aqui.
using System.Text; //este namespace serve para geração de textos longos e manipulação de arquivos de texto em geral. Este usaremos
using System.Data; //este namespace abstrai tudo o que tem a ver com bancos de dados e coleções de dados
using System.Data.SqlClient;//extensão da biblioteca acima, serve para conectar-se com o SQL Server
using System.Net.Mail; //namespace que serve para trabalhar com e-mails

//abaixo o namespace criado por você, toda aplicação ou biblioteca fica dentro de um namespace
namespace MandaConsultaEmail
{

    //este é o nome da classe. Em um programa orientado a objetos as funções (equivalentes as sub's do vb que você já conhece) ficam agrupadas dentro de classes
    class Program
    {
        //o método Main é o método principal de um programa executável, é o ponto de entrada
        //toda a aplicação windows deve ter um método main como este
        //ao dar dois cliques em um programa o windows executará o método Main do programa automaticamente
        //esses argumentos dentro do método Main são parâmetros de linha de comando que você pode passar para o aplicativo
        //o fato de ele ser estático significa que ele deve ser executado diretamente a partir da classe, e não a partir de um objeto da classe (explicação detalhada sobre diferença entre objeto e classe fica para um outro dia)
        static void Main(string[] args)
        {
            //string builder é uma classe que fica dentro de system.text. Ela será usada para criarmos o resultado que você quer por e-mail
            //stringbuilder é a classe e strb é o objeto (instância/exemplo) dessa classe
            //classe é uma categoria de objetos, um esqueleto
            //objeto, como o próprio nome diz, é um exemplo desta categoria

            //classe        //objeto
            StringBuilder   strb = new StringBuilder();

            //se você tivesse uma classe chamada Carro, um objeto desta classe poderia ser um fusca verde placa ngc6417
            //objetos de uma classe são construidos a partir da palavra new. Por exemplo new StringBuilder() cria um novo StringBuilder
            //a função StringBuilder() que tem o mesmo nome da classe StringBuilder é chamada de construtor

            SqlConnection oCon = new SqlConnection(@"Data Source=[[servidor]];Initial Catalog=[[banco_de_dados]];Persist Security Info=True;User ID=[[login]];Password=[[senha]]"); //cria um objeto de conexão com o banco
            //ao criar um objeto de conexão uma string pode ser passada como parâmetro
            //esta string é chamada de connection string e contém instruções para se conectar no SQL, como endereço da máquina, nome do banco, login e password.
            //é comum colocar-se a string de conexão em um arquivo de configuração e não no código, assim se mudar a senha do banco não precisa recompilar o programa. 
            //preceder uma string com @ desabilita as sequências de escape. Usar esse recurso sempre que a string contiver slashes "\" (este foi um erro que cometi escrevendo esse tutorial, até cachorro velho esquece dessas besteirinhas)

            SqlCommand oComm = new SqlCommand("select top 10 * from [[tabela]]", oCon);// cria um objeto-comando. Esse objeto servirá para disparar o comando no banco.
            //como todo comando precisa de uma conexão onde exeutar, passamos oCon (o objeto de conexão criado) como segundo argumento 

            //objetos de comando se criam assim: 
            //new SqlCommand(comandos , conexão)

            oCon.Open(); //antes de executar o comando deve-se abrir a conexão. não SEJE como eu, que sempre esqueço disso.

            SqlDataReader dr = oComm.ExecuteReader(); //cria um leitor de dados e o armazena no objeto dr

            //o SQLCommand oComm possui dois métodos principais, um ExecuteReader e o ExecuteNonQuery. 
            //o ExecuteNonQuery serve para executar comandos que não retornem dados, como insert, update, delete. 
            //o ExecuteReader serve para executar comandos que retornam dados  trazendo esses registros
            //o executereader cria um SQLDataReader internamente, por isso você não precisa dar o comando dr = new SQLDataReader. Um método que cria um objeto (não sendo o seu constructor) é chamado de factory method
            //se o comando for retornar dados crie um SQLDataReader para varrer os dados com SqlDataReader dr = oComm.ExecuteReader().
            //se não retornar dados não crie o datareader, use direto  o  oComm.ExecuteNonQuery()

            //no C# os argumentos do if sempre deverão vir entre parênteses
            if(dr.HasRows) //pergunto se o dr retornou alguma linha
            {
                while (dr.Read()) //read le uma linha e avança para a próxima, como uma barra de rolagem, mas ela só pode avançar, não pode retroceder
                {	
					strb.Append(dr["[[campo1]]"].ToString() + " - " + dr["[[campo n]]"].ToString() + "\r\n"); //adicionando campo i e campo 2 (e uma quebra de linha) no stringbuilder, para cada linha trazida da consulta, exemplo:
                    //strb.Append(dr["cpf"].ToString() + " - " + dr["nome"].ToString() + "\r\n"); //adicionando cpf e nome (e uma quebra de linha) no stringbuilder, para cada linha trazida da consulta
                    //o DataReader dr pode ser indexado de duas formas, pelo nome do campo ou pelo número do campo, exemplo:
                    //dr["cpf"] trará o valor do CPF
                    //dr[0] trará o valor do primeiro campo
                    //dr[1] trará o segundo campo, a lista começa em 0
                }
            }

            //saindo do loop temos que mandar o e-mail


            MailMessage mailMessage = new MailMessage(); //cria um novo objeto do tipo MailMessage chamado mailMessage
            //repare que o C# é sensível a maiúscula / minúscula, portanto mailMessage é diferente de MailMessage
            //eu particularmente não gosto de colocar o nome de um objeto igual ao nome de sua classe, mas você encontrará muito disso
            //você pode preceder seus objetos com uma abreviação do tipo de classe que eles são, por exemplo:
            //MailMessage mmFuncionarios = new MailMessage(); 
            
            mailMessage.From = new MailAddress("[[remetente]]"); //cria um objeto do tipo endereço de e-mail que é o e-mail do remetente 
            mailMessage.Sender = new MailAddress("[[remetente]]"); //remetente também
            mailMessage.To.Add("[[destinatario]]"); ////e-mail do destinatário
            mailMessage.CC.Add("[[com copia]]"); // é o com cópia

            //a diferença entre sender e from eu não sei, deve-se pesquisar no msdn

            mailMessage.Subject = "Assunto do email";

            //joga todo o texto do stringbuilder para o corpo do e-mail, com a lista completa do que você quer
            mailMessage.Body = strb.ToString();

            //define se o corpo do e-mail será html ou não
            mailMessage.IsBodyHtml = false;


            //SmtpClient é uma classe que funciona como o outlook, é um client de SMTP (o protocolo de comunicação utilizado por e-mails)
            SmtpClient smtpClient = new SmtpClient();

            smtpClient.Host = "[[servidor de e-mail]]"; //servidor de e-mail
            smtpClient.Port = 587;	//25; //porta, a 25 é a padrão de e-mail sem criptografia (era padrão na época deste tutorial, hoje o padrão é 587)
            smtpClient.UseDefaultCredentials = true; //true em grande parte dos casos, a saber, se o servidor se autentica com NTLM ou baseado em Kerberos. Caso seja true, o servidor usará as credenciais do usuário logado antes de enviar o e-mail. Leia:
			
				//http://msdn.microsoft.com/pt-br/library/system.net.mail.smtpclient.usedefaultcredentials(v=vs.110).aspx
				//http://msdn.microsoft.com/pt-br/library/system.net.credentialcache.defaultcredentials(v=vs.110).aspx
            
            //NetworkCredential  é uma classe que cria objetos que agrupam login e senha de redes, funciona assim:
            //new System.Net.NetworkCredential(login, senha);
            //no caso estamos usando o login e senha da intranet para mandar e-mail pelo servidor da mandic, considerando que intranet@lidertel.com.br é um e-mail válido na mandic
            smtpClient.Credentials = new System.Net.NetworkCredential("[[login do email]]", "[[senha do email]]");

            //setar isso para true em caso de gmail ou outro provedor que use ssl
            //smtpClient.EnableSsl = true;

            smtpClient.Send(mailMessage); //usa o client para enviar o message


            //depois de usar o connection, se não precisar mais, fexar e dar dispose()
            oCon.Close();
            oCon.Dispose();

            //o certo é fazer o dispose dentro de um bloco try... finally, mas depois falaremos disso. 

        } //fim do método main
    }//fim da classe Program
}//fim do namespace

//regras de boa conduta ao programar:
//1) métodos estáticos apenas quando forem ser executados por um programa de fora ou forem executados a partir da classe e valem para a classe inteira, independente do objeto
//2) métodos estáticos são stateless, ou seja, não devem alterar o estado interno dos objetos, campos e variáveis
//3) crie uma classe por arquivo.cs, sendo que o arquivo deve ter o mesmo nome que a classe
//4) métodos, variáveis, propriedades, campos, atributos, namespaces e classes devem ter nomes significativos
//5) identificadores compostos de mais de uma palavra devem ter a primeira letra de cada palavra em maiúscula





Ao escrever esse mini - tutorial me surpreendi com a quantidade de informação que precisa ser passada para uma pessoa nova em programação.
É diferente  de uma pessoa  nova em uma linguagem / ambiente / framework mas que já saiba programar o básico.

No caso desse exemplo, ele fazia uma consulta em umas tabelas do banco de dados do sistema Totvs RM Labore, retornando os dados em forma de texto no corpo do e-mail (podia muito bem ser um csv ou excel).
Omiti, obviamente, o nome do banco, da tabela e os parâmetros de conexão com o banco.

Esse é um tutorial sem passar pelas etapas "obrigatórias" de um tutorial de programação: palavras reservadas, declaração de variáveis, tipos de dados, operadores aritméticos, if ... etc não necessariamente nesta ordem.
Também muitas teorias são simplesmente ignoradas aqui: pulamos direto para a parte prática e o código.

Pelo menos o código está explicado linha a linha.

quinta-feira, 28 de novembro de 2013

Testar se uma variável é undefined no javascript

Para testar se uma variável é undefined ou null pode-se compará-la com as palavras chave undefined e null usando os operadores:
== (valor igual),
!= (valor diferente),
=== (estritamente igual, mesmo valor e tipo),
!== (diferente, tipo diferente)

No script abaixo existe uma variável y não declarada. Por causa dela uma exceção é gerada e tratada no catch logo abaixo.

Sempre é necessário verificar se uma variável/objeto é nula ou undefined antes de se usá-la, chamar seus métodos ou alterar suas propriedades.
É a não verificação dessas duas condições que sempre causa erros de script na página (objetos que não existem, que são nulos etc...).

O try ... catch vai garantir que você encontre o erro mesmo que esqueça dessas coisas essenciais, e seu script não para de funcionar, mesmo com erro.

 

 
 
  

Teste de Undefined

   var x;
   
   try
   {
    if(x == null)
    {
     document.getElementById('resultado').innerHTML   += "x é == null 
";
    }
    else
    {
     document.getElementById('resultado').innerHTML   += "x é != null 
";
    }
    
    
    if(x === null)
    {
     document.getElementById('resultado').innerHTML   += "x é === null 
";
    }
    else
    {
     document.getElementById('resultado').innerHTML   += "x é !== null 
";
    } 




    if(x == undefined)
    {
     document.getElementById('resultado').innerHTML   += "x é == undefined 
";
    }
    else
    {
     document.getElementById('resultado').innerHTML   += "x é != undefined 
";
    }
    
    
    if(x === undefined)
    {
     document.getElementById('resultado').innerHTML   += "x é === undefined 
";
    }
    else
    {
     document.getElementById('resultado').innerHTML   += "x é !== undefined 
";
    } 





    if(y == null)
    {
     document.getElementById('resultado').innerHTML   += "y é == null 
";
    }
    else
    {
     document.getElementById('resultado').innerHTML   += "y é != null 
";
    }
    
    
    if(y === null)
    {
     document.getElementById('resultado').innerHTML   += "y é === null 
";
    }
    else
    {
     document.getElementById('resultado').innerHTML   += "y é !== null 
";
    } 




    if(y == undefined)
    {
     document.getElementById('resultado').innerHTML   += "y é == undefined 
";
    }
    else
    {
     document.getElementById('resultado').innerHTML   += "y é != undefined 
";
    }
    
    
    if(y === undefined)
    {
     document.getElementById('resultado').innerHTML   += "y é === undefined 
";
    }
    else
    {
     document.getElementById('resultado').innerHTML   += "y é !== undefined 
";
    } 
   }
   catch(e)
   {
    alert(e.message);
   }

Peguei no stack overflow:

 http://stackoverflow.com/questions/7041123/test-if-something-is-undefined-in-javascript

quarta-feira, 27 de novembro de 2013

Wildcards nos seletores JQuery

O JQuery pode ser usado com Wildcards / Coringas nos seletores.

Queria aplicar uma regra de formatação e validação em todos os campos input onde deveriam ser inseridas datas, no entanto, como é um sistema legado, os elementos html não possuem ID's, ou pelo menos não alguns que eu tenha controle. Também não é possível no meu sistema atual atribuir classes aos elementos sem alterar o software que hera o html.

Minha última opção seria confiar nos seletores jQuery e na propriedade name dos inputs. Uma vantagem é que, na minha aplicação, todos os inputs de data tem o prefixo "dt_" no nome. Tudo que eu precisava era de uma forma de selecionar todos os inputs que começavam com "dt_".

O jQuery permite seletores por tipo de tag e atributo, então para selecionar inputs seria $("input[atributo='valor']"). No entanto não existe apenas o operador "=". Os operadores possíveis são:

*= (contém)
$= (termina com)
^= (começa com)

Então, para selecionar os que começam com "dt_" seria assim:

            //validação para campos data
            $("input[name^='dt_']").keyup(function () {
                if (this.value != this.value.replace(/[^0-9\/]/g, '')) {
                   this.value = this.value.replace(/[^0-9\/]/g, '');
                }
            });

Postagens populares

Marcadores

delphi (60) C# (31) poo (21) Lazarus (19) Site aos Pedaços (15) sql (13) Reflexões (10) .Net (9) Humor (9) javascript (9) ASp.Net (8) api (8) Básico (6) Programação (6) ms sql server (5) Web (4) banco de dados (4) HTML (3) PHP (3) Python (3) design patterns (3) jQuery (3) livros (3) metaprogramação (3) Ajax (2) Debug (2) Dicas Básicas Windows (2) Pascal (2) games (2) linguagem (2) música (2) singleton (2) tecnologia (2) Anime (1) Api do Windows (1) Assembly (1) Eventos (1) Experts (1) GNU (1) Inglês (1) JSON (1) SO (1) datas (1) developers (1) dicas (1) easter egg (1) firebird (1) interfaces (1) introspecção (1) memo (1) oracle (1) reflexão (1)