Boleto Bancário em ASP.NET

Para quem quer implementar boleto bancário em ASP.NET e não quer perder tempo fazendo tudo, há um componente que é mão na roda: Boleto.Net. Segue abaixo descritivo retirado do site:


"Boleto.Net é um componente desenvolvido em C# e ASP.Net e contempla as seguintes funcionalidades:
Emissão e Impressão de Boletos Bancários
Geração de Arquivo de Remessa (CNAB 240 e 400)
Leitura do Arquivo de Retorno (CNAB 240 e 400)
Atualmente estamos implementando mais alguns bancos e toda colaboração será importante. Nosso objetivo é implementar todos os bancos brasileiros.
A versão 2.0 está disponível. Nessa versão contempla leitura e remessa de arquivos CNAB 400/240."


Uma boa iniciativa por parte do pessoal. Todo apoio é importante! Na página do site deles há toda informação que precisa para desenvolver: tanto o componente quanto exemplo. Os bancos homologados são: Banco do Brasil, Bradesco, Santander, Itaú e BRB. Já ajuda bastante...

Tocando/Emitindo som com C#

Dica rápida para emitir um som com C# usando a API do Windows: basta importar a função PlaySound. Crie a lista enumerada e importe a DLL utilizando os seguintes códigos:


        // FLAGS DE SOM
        [System.Flags]
        public enum PlaySoundFlags : int
        {
            SND_SYNC = 0x0000,
            SND_ASYNC = 0x0001,
            SND_NODEFAULT = 0x0002,
            SND_LOOP = 0x0008,
            SND_NOSTOP = 0x0010,
            SND_NOWAIT = 0x00002000,
            SND_FILENAME = 0x00020000,
            SND_RESOURCE = 0x00040004
        }


        // IMPORTAÇÃO DO COMPONENTE DE SOM
        [DllImport("winmm.dll", EntryPoint = "PlaySound", SetLastError = true, CharSet = CharSet.Unicode, ThrowOnUnmappableChar = true)]
        private static extern bool PlaySound(string szSound, System.IntPtr hMod, PlaySoundFlags flags);

Não precisa copiar a DLL para a aplicação uma vez que ele busca na biblioteca do próprio Windows.

Para tocar, execute o método (exemplo):


PlaySound("sound.wav", new System.IntPtr(), PlaySoundFlags.SND_ASYNC);

Sempre use a flag PlaySoundFlags.SND_ASYNC (forma assíncrona). É aconselhável usar ela do que PlaySoundFlags.SND_SYNC (forma síncrona) se estiver trabalhando com outro processamento em paralelo. Ou seja, após o som, se for realizar algum outro método ou trecho de código. De forma assíncrona ele irá tocar e continuar com o processamento do código que tiver logo abaixo (paralelo). De forma síncrona pode haver lentidão no processo pois à vezes o som pode demorar a tocar ou ter que esperar terminar para prosseguir (contínuo). Faça os testes antes para ver o diferencial.

Agora sim! Volte ao post do Microterminal e adicione sua função para tocar um som quando apertar * (asterisco).

Problema no ASP.NET Menu no Chrome e Safari

Me veio esse problema a alguns dias ao usar o ASP.NET Menu. Nunca tinha usado para desenvolver menus. Geralmente uso o componente da DevExpress, o ASPxMenu, no qual consiste em um menu robusto, flexível e mil vezes melhor que o menu convencional. Pois bem... Quando reparei, vi que no Chrome não funcionava... Uai! Procurando informações, obtive que o ASP.NET não renderiza direito o menu diante desses navegadores e que a solução era adicionar uma configuração de browser na aplicação. Li vários artigos mas só Seiti mostrou em seu blog uma forma mais elegante e funcional de corrigir (clique aqui para ver na íntegra).

Basicamente, crie a pasta App_Browsers em sua aplicação e adicione um arquivo safari.browser. Em seguida adicione o trecho abaixo:


<browsers>
    <browser refID="Safari1Plus">
        <controlAdapters>
            <adapter controlType="System.Web.UI.WebControls.Menu" adapterType="" />
        </controlAdapters>
    </browser>
</browsers>


Agora funciona! Mais detalhes veja o blog de Seiti.

Wordpress em ASP.NET

O Wordpress é um dos melhores gerenciadores de blogs que eu já vi. Muito completo e de código aberto, sua flexibilidade de utilizar add-ons (plugins) é o que permite dar-lhe grande escalabilidade. Visite o link para conhecer... Já tinha utilizado a ferramenta algumas vezes e achei bem intuitiva e fácil de usar (além de manipulá-la). Então dei uma olhada na net e, infelizmente, não há versões dele em ASP.NET. Então pensei: porque não fazer?


Comecei a dar uma olhada no código analisando a reutilização das páginas. Vendo por alto dá para sentir como o negócio foi bem feito! Surpreendente o que foi feito em PHP... Voltando... Primeiro gerei uma cópia do HTML de algumas páginas. Como fiz isso? Exibindo a página no navegador, mostrando o código-fonte (em HTML) e salvando. Só assim que dá pois o código PHP está misturando com código HTML. É chato, trabalhoso e principalmente nunca fica do jeito que queremos. Mas ficou quase parecido.

Depois fiquei vendo que não vai ser tão fácil assim. Parei e desisti! Muito cansativo... Pelo menos já tenho o HTML de algumas páginas (estático). Fiquei enrolando por um tempo e precisava ter um CMS para sites. O Wordpress já é um CMS então pensei em agregar um módulo para fazer cadastros pegando uma tabela no banco de dados e transformando em formulário. Pelo menos isso! Feito...


Hoje, ao menos, já tenho um cadastro! Isso poderia ser feito por Linq? Claro! Isso é Linq... Apenas coloquei na casca do Wordpress. Ou seja, o que fiz, qualquer um poderia ter feito. Agora o mais difícil é fazer os demais módulos. Ou seja, fazer o Wordpress... Complicado! Não sei se conseguirei fazer. Talvez desista no meio do caminho ou não. Futuro indeciso. Se um dia terminar coloco no Google Code ou em qualquer repositório para download.

Fazendo umas pesquisas no Google, encontrei o site de David Pirek. Ele fez um gerenciador de conteúdo para blogs em ASP.NET (em MVC ainda) de forma bem mais reduzida que o Wordpress mas que tem o mesmo objetivo (menos a casca). Bem interessante! Para conhecer veja o projeto ASP.NET CMS 3.0. Acho que quebra um galho... Também, para ver o demo e a versão 4.0 clique aqui. A minha idéia de copiar o Wordpress e transformar em ASP.NET veio daí e no grande poder que a ferramenta disponibiliza.

Resumo
Projeto: Wordpress em ASP.NET
Linguagem: C# 3.5
Banco de Dados: SQL Server
Plugins: JQuery, Mootools, ASP.NET AJAX, NicEdit WYSIWYG
Andamento: 1%

Obs: Depois estava lendo que há um "armengue" de colocar o Wordpress em PHP e o blog em ASP.NET para funcionar. Parece que se colocar o Wordpress em um diretório e o blog em outro e configurar como aplicações separadas no IIS (lembrando que pode ter o PHP no IIS com FastCGI) dá pra fazer funcionar. Só que terá que programar o blog para puxar as informações. Não testei, mas fica a dica para quem quiser tentar...

Comunicando com microterminal em ASP.NET

Quem já foi em supermercado e nunca viu aquelas maquininhas que o operador fica digitando? Pois é... estamos falando dela mesma. Parece ser fácil seu uso, mas quem começa a trabalhar com elas é de perder os cabelos.


Nesse artigo veremos como comunicar com um microterminal via TCP/IP e trocar informações (ida e volta). Para isso vamos utilizar o modelo da Gertec MT 720. Uma breve descrição do aparelho e seu uso (retirado daqui):

"O MT 720 é um excelente microterminal que opera em rede Ethernet com protocolos TCP-IP. Seu teclado com 20 teclas programáveis pode ser utilizado com funções específicas de atalhos para agilizar a operação.
As teclas re-legendáveis permitem a identificação da função de cada tecla. O display com back light (iluminado), com 20 caracteres por 2 linhas, permite facilmente a visualização da informação, principalmente em ambientes que possuem pouca iluminação, como bares noturnos, por exemplo.
Através de uma porta de teclado (AT/PS2) e mais 3 portas Seriais (RS-232) é possível a conexão de periféricos como: Leitor de Código de Barras, Display de Cliente, Balança, Impressora, etc.
O MT 720 é ideal para aplicações de Cartão de Consumo, soluções para Bares, Lanchonetes, Restaurantes Self-Service, Livrarias, Papelarias, apontamento de produção em Indústrias."
Na própria página do dispositivo (citada acima) tem alguns downloads de arquivos, dentre eles alguns códigos-fontes com exemplos de como fazer a comunicação bem como realizar as operações pelas quais foi criado. Um porém: só tem disponíveis nas linguagens C++, Delphi e VB (não é VB.NET).

Daí pensamos: "sem problemas! é só converter pra VB.NET a partir do VB"... Também pensei nisso e não consegui! Dando uma olhada de perto no código-fonte dá para saber que as proezas encontradas são só possíveis por artifícios que a linguagem oferece: por exemplo, ponteiros. Quem já programou em VB via a grande flexibilidade da linguagem de fazer tudo o que quer e do jeito que era mais conveniente. Maravilha! Pena que tenhamos que seguir certos padrões. Fica a dica: se não quiser perder tempo, pegue logo o código prontinho lá na página do fabricante (vem também no CD quando compra o aparelho) e utilize. De preferência use o Delphi e em seguida em VB. Se quiser aventurar vamos com C#...

Se escolheu C# siga lendo pois, em diante, veremos como fazer... Teremos os seguintes objetivos na implementação:

  1. Criar uma única aplicação que irá receber e enviar os dados;
  2. Exibir o que foi digitado tanto no microterminal quanto no monitor.


Instalação

Leia o manual do usuário aqui. Em resumo: ligue o microterminal na rede elétrica e conecte na porta traseira um cabo RJ-45 no dispositivo e a rede. Em seguida configure, no microterminal, o IP do Servidor (no meu caso, considerei minha máquina local com o IP 192.168.1.100, por exemplo). Demais configurações a seu gosto...



Implementação

Criemos um Windows Form. Coloquei alguns controles para embelezar a aplicação...



O mais importante é adicionar um objeto Timer. Os demais coloquei para gerar a aplicação final (que ficará no tray - perto do relógio - e outras coisas fru-frus). Configure seu Timer com Interval de 50. Pegue a DLL pmtg.dll e copie para sua aplicação. Eu disse copie! Você não conseguirá aplicar Reference sobre ela. Clique com o botão direito sobre a DLL e escolha Properties. Em Copy to Output Directory coloque Copy Always.



Agora vamos ao código! Clique sobre o WinForm e escolha View Code. Cole os códigos abaixo para que possamos usá-las no form:


        // VARIÁVEIS
        IntPtr v_Hwnd;
        int statusCard;
        int statusSerial;
        int MsgReceiveData = 1;
        string[] dados = new string[255];


        // INICIALIZAÇÃO DE FUNÇÕES EXTERNAS
        [DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        public static extern int mt_startserver(IntPtr mywhnd, int conecmsg, int commumsg);
        [DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        public static extern void mt_finishserver();
        [DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        public static extern int mt_getkey(int id, StringBuilder str);
        [DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        public static extern int mt_backspace(int id);
        [DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        public static extern int mt_dispstr(int id, string str);
        [DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        public static extern int mt_dispch(int id, char ch);
        [DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
        public static extern int mt_dispclrln(int id, int lin);
        [DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]]
        public static extern int mt_gotoxy(int id, int lin, int col);



Em seguida adicionamos as duas funções primordiais: início (quando carregar o formulário) e término (quando fechar o formulário):


        private void MicroTerminal_Load(object sender, EventArgs e)
        {
            v_Hwnd = this.Handle;
            statusCard = 0;
            statusSerial = 0;
            if (mt_startserver(v_Hwnd, 0, MsgReceiveData) == 1)
            {
                temporizadorLista.Enabled = true;
            }
            else
                MessageBox.Show("Não foi possível carregar os módulos de conexão à leitora!");
        }



        private void MicroTerminal_FormClosed(object sender, FormClosedEventArgs e)
        {
            temporizadorLista.Enabled = false;
            mt_finishserver();
        }



Lembrando que esses eventos devem estar configurados (não é apenas copiar e colar o código, lembra? deve-se indicar lá em Events do Form). Com isso, ao fazer o primeiro teste, sua aplicação já estará recebendo dados do microterminal. Em seguida devemos adicionar um evento Tick ao Timer. Ou seja, a cada 50 milisegundos (lembra que colocamos com esse valor) irá ser executado um determinado método.

Antes disso vamos criar um método que irá limpar a tela do microterminal e reiniciar os dados de entrada:


                 private void ReiniciaEntrada(int i)
        {
            // Limpa as duas linhas e o que foi armazenado
            dados[i] = "";
            mt_dispclrln(i, 1);
            mt_dispclrln(i, 2);
            // Coloca o cursor na primeira linha e prepara o display
            mt_gotoxy(i, 1, 0);
            mt_dispstr(i, "Numero: ");
            mt_gotoxy(i, 2, 0);
        }


Enfim adicionamos o código que irá ler temporariamente cada leitora conectada à rede e coletar/processar os dados de acordo com o que desejar. No meu caso deixei o seguinte:


        private void temporizadorLista_Tick(object sender, EventArgs e)
        {
            StringBuilder rntStr = new StringBuilder();
            int i = 0;
            // Loop em toda faixa de Ips úteis: cada leitora conectada na rede
            while (i < 255)
            {
                // Captura algo do teclado
                if (mt_getkey(i, rntStr) == 1)
                {
                    string chrAsHex = ((int)rntStr[0]).ToString("x");
                    // Entrada do display caso seja um número
                    if ((chrAsHex == "3030") || (chrAsHex == "30") || (chrAsHex == "31") || (chrAsHex == "32") || (chrAsHex == "33") || (chrAsHex == "34") || (chrAsHex == "35") || (chrAsHex == "36") || (chrAsHex == "37") || (chrAsHex == "38") || (chrAsHex == "39"))
                    {
                        if (dados[i].Length >= 20)
                            dados[i] = dados[i].Substring(0, 19) + rntStr[0];
                        else
                            dados[i] += rntStr[0];
                        mt_dispch(i, rntStr[0]);
                    }
                    // Se for um ENTER, dá a entrada na tela para mostrar
                    else if (chrAsHex == "d")
                    {
                        // Captura e trata a entrada
                        if (dados[i] != "")
                        {
                            // Faz o processamento do que desejar em dados[i]
                        }
                        // Limpa tela
                        ReiniciaEntrada(i);
                    }
                    // Se for um ESC, apaga tudo
                    else if (chrAsHex == "1b")
                    {
                        // Limpa tela
                        ReiniciaEntrada(i);
                    }
                    // Se for backspace apaga último caractere do display
                    else if (chrAsHex == "8")
                    {
                        if (dados[i].Length > 0)
                            dados[i] = dados[i].Substring(0, dados[i].Length - 1);
                        mt_backspace(i);
                    }
                    // Se apertar * toca o som
                    else if (chrAsHex == "2a")
                    {
                        // Toca um sonzinho... depois publico o código de tocar som!
                    }
                }
                i++;
            }
        }


Feito! Rode sua aplicação e digite algo no teclado do microterminal e verá que o que está sendo digitado está indo tanto para a aplicação quanto para o display (no microterminal). A saída seria algo do tipo:


Se precisar de saída na tela crie um outro WinForm que ocupe toda tela (sua) e captura o que está no display do microterminal. Assim é mais fácil! Ou faça do jeito que sua imaginação mandar! O mais difícil já passou...

Para quem quiser capturar os IPs de cada microterminal, utilize os métodos:


[DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern TTABSOCK mt_connectlist();

ou


[DllImport("pmtg.dll", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern StringBuilder mt_ipfromid(int id);



Nessas funções tem algumas particularidades muito chatinhas de se trabalhar (veja no manual das funções) por isso deixei de lado. Principalmente a classe:


    [StructLayout(LayoutKind.Sequential)]
    public struct TTABSOCK
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)]
        public UInt32[] TSOCK;
    }


Quem quiser se aventurar nela, fica aí a dica. Esse artigo merecia até uma vídeo-aula, mas a preguiça às vezes é muito forte! É até legalzinho ter esses desafios, mas às vezes se torna muito chato quando não consegue. Enfim, quanto menos se estressar, melhor! Então tente usar as implementações que já a Gertec já disponibilizou, caso não queira aventurar, a menos que precise de algo mais específico.
Falar que nem Marcoratti: "eu sei, é apenas ASP.NET, mas eu gosto!"

Melhorando o desempenho de consultas (SELECT) em tabelas grandes no SQL SERVER

"Tenho uma tabela com mais de um milhão de registros. Faço uma consulta... um simples SELECT... mas está demorando muito para retornar. O que fazer?"
Essa é a pergunta que você se faz nessa situação. Todo programador sabe trabalhar com banco, mas nem sempre sabemos utilizar da melhor forma. Um DBA já é craque na situação e sabe a melhor forma de melhorar o desempenho de uma consulta. A dica do dia é: índices! Se você não sabe o que são índices, veja essa matéria aqui de Thiago Pastorello que explica de forma bem compreensiva. Também recomendo que leia também esse artigo da Compute-rs onde explica as vantagens e desvantagens de usar índices.

É só isso? Talvez. Se você entedeu o significado de índices lendo os dois artigos (referência) e fez o que irei demonstrar abaixo pode ser que resolva. Na net você irá encontrar outros artigos semelhantes que irão mostrar outros caminhos que podem ajudar melhor. Aqui será de forma simplificada... Vamos?

Abra o Microsoft SQL Server Management Studio, conecte-se a base de dados e clique em New Query. Escreva a consulta que deseja avaliar e corrigir para ficar mais rápida. No meu caso irei executar uma Stored Procedure que contêm várias sub-consultas com manipulação de agrupamento tais como COUNT, SUM, etc. Na barra de ferramentas marque a opção Include Actual Execution Plan (Incluir Plano de Execução Atual).


Agora clique em Execute ou pressione F5 para executar a query e avaliá-la. Aguarde até que finalize completamente. Vá na última aba abaixo de Plano de Execução e veja os resultados.


Passando o mouse por cima de cada item irá ser exibidos detalhes acerca do custo de processamento. Depois procurem ai no Google mais explicações sobre cada item. Mas vamos nos atrelar a essa mensagem verde. Note que o próprio SQL Server informa que há indices ausentes! Vamos criá-los?

Clique com o direito sobre a mensagem e escolha Detalhes de Índices Ausentes.


Ao clicar, irá aparecer outra tela com um query de criação do índice, exemplo:

/*
Detalhes de Índice Ausentes de SQLQuery1.sql - SERVIDOR.Mailing (thiago (53))
O Processador de Consultas estima que a implementação do índice a seguir pode melhorar o custo da consulta em 99.7047%.
*/
/*
USE [Mailing]
GO
CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [dbo].[News_Envio] ([id_campanha])
GO
*/
 
A consulta de criação está praticamente pronta bastanto apenas dar um nome para o índice e remover o comentário, deixando da seguinte forma:
 
USE [Mailing]
GO
CREATE NONCLUSTERED INDEX PI_Index_Envio_Campanha
ON [dbo].[News_Envio] ([id_campanha])
GO

Pressione F5 ou Execute esse bloco de instruções para criar o índice. Antes de testarmos, vamos atualizar os índices e suas estatísticas.

Vá na tabela desejada, na opção de Índices e escolha Reorganizar Índices. Veja o nível de fragmentação e dê OK. Em seguida execute:

UPDATE STATISTICS News_Envio

No caso substitua News_Envio pelo nome de sua tabela. Agora execute novamente o primeiro processo e verá um ganho significativo de velocidade de consulta. O que levava 1 minuto para executar, em menos de 1 segundo obtêm-se o resultado. Bom né?

Aprecie com moderação o uso de índices e leiam as referências para saber quais situações onde é vantagem ou não o uso deles.

Volta dos artigos

Olá pessoal...
Como prometido, estarei retormando os artigos ajudando a comunidade e programadores. Uma nova seção que teremos é a divulgação de vagas e cursos (gratuitos ou bem baratinhos) interessantes que todo desenvolvedor deveria participar.
Também estava criando umas vídeos aulas para auxiliar em algumas matérias, já que a curva de aprendizado vendo é mais acentuada do que lendo (tática de professor - falei bonito, eheheh). Mas isso logo que tiver um tempinho sobrando.
Outra coisa que notei, logo após a pausa, é que alguns artigos meus foram copiados quase na íntegra e publicado em outros blogs sem referência (uns 3). Bem... podem copiar, alterar e divulgar ao menos que tenham a referência de onde buscaram. Sem problemas! O que temos hoje na net é a contribuição de ínumeras pessoas que se dedicaram boa parte de seu precioso tempo na leitura de artigos de vários outros escritores para elaboração dos próprios. Nada aqui é inventado e sim compilado conhecimento de contribuidores (pela net, livros e revistas).
Sem mais delongas... voltemos a nossa programação normal!

Férias

Olá pessoal!

Depois um tempo sem postar nada na próxima semana irei retomar com novos artigos!