Feliz Natal e Até Ano que Vem

Pessoal,

Feliz Natal, Próspero Ano Novo, tudo de bom, etc e tal para todos vocês!

Infelizmente em Dezembro não tive muito tempo para escrever artigos, mas para o ano teremos boas matérias. Estou preparando uma série de artigos para o tema Newsletter que vai ser show de bola. Então, divirtam-se... Dia 10/01/2011 voltamos com as novidades!

Gerar Thumbnail de um HTML

Nesse artigo veremos como gerar um Thumbnail (ou Screenshot) de um HTML. Por exemplo: às vezes queremos ter uma prévia de uma página e não temos como vê-la a não ser abrindo-a. Então geremos o thumb delas e coloquemo-as em um DataList. No caso não colocarei no DataList... apena mostrarei como gerar o thumb. Usaremos o componente WebsitesScreenshot. Essa DLL permite:
  • Gerar um thumb através de um arquivo HTML local (indicando o arquivo ou inserindo o código-fonte);
  • Gerar um thumb através de uma URL;
  • Salvar o thumb gerado ou exibir na tela, etc.
É um poderoso componente que você pode manipular de várias formas e chegar a bons resultados. Irei mostrar algo bem simples: gerarei um thumb de uma URL e exibirei em uma imagem. Vamos?

Crie uma página (Web Form) qualquer onde será exibida o thumb. Adicione um Image e no seu atributo ImageUrl indique o valor Thumb.ashx. Agora criemos um Generic Handler chamado Thumb.ashx no projeto. Dentro do ProcessRequest coloque o seguinte trecho de código ficando da seguinte forma:

public void ProcessRequest (HttpContext context) {
        WebsitesScreenshot.WebsitesScreenshot ComponenteThumb = new WebsitesScreenshot.WebsitesScreenshot();
        WebsitesScreenshot.WebsitesScreenshot.Result ResultadoCaptura = ComponenteThumb.CaptureWebpage("http://www.google.com.br/");
        if (ResultadoCaptura == WebsitesScreenshot.WebsitesScreenshot.Result.Captured)
        {
            System.Drawing.Image thumb = ComponenteThumb.GetImage().GetThumbnailImage(140, 110, null, new IntPtr());
            MemoryStream ms = new MemoryStream();
            context.Response.ContentType = "image/png";
            thumb.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
            ms.WriteTo(context.Response.OutputStream);
        }
        ComponenteThumb.Dispose();
    }

Não se esqueça de adicionar o namespace System.IO; lá. O resultado seria algo do tipo:


A depender dos parâmetros que você trabalhar e qualidade dos objetos, o resultado final vem a ser melhor do que isso. O que mostrei foi o básico do componente!

Se fosse para gerar o thumb de um arquivo HTML local ou código-fonte, bastaria inserir o seu conteúdo em uma string e depois usar o seguinte método:

string HtmlArquivo = "Você visitou o blog de Thiago Marçal!";
WebsitesScreenshot.WebsitesScreenshot.Result ResultadoCaptura = ComponenteThumb.CaptureHTML(HtmlArquivo);

E o resultado seria:


Está pequenininho, mas é thumb! Mais informações você pode obter no site oficial.

Flash Control - Componente ASP.NET para Incluir Flash nas Páginas

Você pode estar se perguntando? Porque usar esse componente ao invés de usar embed, object do próprio HTML? Bem, abaixo tem uma algumas vantagens de sua utilização:

  • Funciona com o framework 2.0, 3.0, 3.5 e 4.0;
  • Funciona em conjunto com o ASP.NET AJAX;
  • Cross browser;
  • Passagem de variáveis para o Flash e comunicação JS, etc.

Essas e outras vantagens o componente lhe dá para não ter dores de cabeça. O Flash Control ainda lhe resolve o problema do flash sumir quando dado um PostBack. Vamos lá? É bem simples seu uso. Primeiro baixe a DLL do componente aqui (há 2 versões dela: paga e a free - pegue a free). Adicione a DLL FlashControl.dll na pasta Bin de seu projeto. Na página que queira exibir registre a DLL e invoque-a usando os seguintes trechos de códigos:

<%@ Register Assembly="FlashControl" Namespace="Bewise.Web.UI.WebControls" TagPrefix="Bewise" %>


<Bewise:FlashControl ID="FlashControlEmbed" runat="server" MovieUrl="~/arquivo.swf" BrowserDetection="False" Height="200px" Width="200px" />

Pronto! Mais informações e outras opções (transparência, FLV, parâmetros, etc) podem ser encontradas na página de Faq deles.

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!

Enviar e-mail em ASP.NET usando o GMail com conta no Google Apps

Um artigo bem simples que se encontra na net para envio de e-mail em C# é esse aqui. Um post bem simples e explicativo de como fazer o envio usando o SMTP do GMail. Mas não era bem isso que eu queria abordar (também) já que disponibilizei o link para o post ensinando como. Quem não conhece o Google Apps já deveria dar uma olhada pois é um conjunto de soluções empresariais que ajuda na redução de custos de TI dando uma maior produtividade. Uma delas é a criação de e-mails tendo um domínio externo. Vou dispensar explicações (nota: tem a versão free e paga)... vamos à "implementação". Suponhamos que eu tenha o domínio www.thiagomarcal.com.br e que esteja configurado para o Google Apps. Lá eu criei um e-mail contato@thiagomarcal.com.br e agora quero usá-lo para fazer o envio de e-mails. Basta eu seguir o post citado anteriormente que é possível fazer o envio com os seguintes dados:
  • SMTP: smtp.gmail.com
  • Sender: contato@thiagomarcal.com.br
  • Senha: 123456
  • Porta: 587
  • Ssl: true
Obviamente a senha é fictícia... apenas usando para fins didáticos, mas que realmente muita gente usa. Então, tudo certo! Faz-se um envio e dá o seguinte erro:

The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.5.1 Authentication Required. Learn more at

O servidor SMTP requer uma conexão segura ou o cliente não foi autenticado. A resposta do servidor foi: 5.5.1 Autenticação solicitada Saiba mais em

Se garantir que os dados estão todos certos e já testou com outra conta (e fez o envio corretamente) faça o seguinte: mude a senha! Senha fraca ou padrão (que nem 123456) o GMail bloqueia a autenticação e não deixa enviar.

Vulnerabilidade de Segurança no ASP.NET

Recentemente, em um congresso internacional, descobriu-se um problema de vulnerabilidade em sistemas ASP.NET através do web.config. O problema afeta todas as versões do framework... A matéria completa de como é o ataque e de como se proteger podem ser lidos nesses posts de Scott Guthrie:
  1. Important: ASP.NET Security Vulnerability
  2. Frequently Asked Questions about the ASP.NET Security Vulnerability
A priori, para impedir o ataque, proteja sua aplicação fazendo com que os erros não sejam exibidos para o cliente. No web.config adicione as seguintes tags:

<configuration>
   <system.web>
      <customErrors mode="On" defaultRedirect="~/Erro.aspx" />
   </system.web>
</configuration>

Assim, toda vez que ocorrer um erro, irá ser redirecionado para uma tela específica.

URL Rewriter - Escreva URL Amigáveis em ASP.NET

A URL Rewriter permite mascarar o endereço original por um novo endereço mais seguro e amigável. Se temos o endereço:

http://thiagomarcal.blogspot.com/noticas.aspx?id_noticia=123

Podemos re-escrevê-la da seguinte forma:

http://thiagomarcal.blogspot.com/noticias/123

Ou de outras formas conforme o mascaramento desejado. Para fazer o mascaramento é preciso do componente URL Rewriter instalado no IIS. Ele é gratuito e é instalado facilmente. Para cada web-site é configurado um mascaramento de endereços que automaticamente ele faz a conversão logo que requisitado.
Não vou entrar em detalhes do processo de instalação e configuração aqui pois no site oficial tem um vídeo (logo na Home), bastando seguir o passo-a-passo, que irá conseguir deixar conforme deseja. Também há disponível vários tutoriais que auxiliam no processo bem como funções avançadas. Clique aqui para visitar o site da Micrososft URL Rewriter.

PagSeguro com ASP.NET (C#)

O PagSeguro é uma das melhores soluções para pagamento on-line que já usei. Muito fácil de usá-la e integrá-la em qualquer sistema. Vantagens são inúmeras e facilidade bem além da conta. No site você encontra bastante informações de como utilizá-la bem como códigos-fonte. Teoni Valois mostra no vídeo abaixo como realizar a integração de forma muito fácil então dispensarei minhas explicações.


Nesse link aqui você obtêm o Framework, Loja-Exemplo e o Test Server. Para quem estiver com problema do retorno automático dando FALSO, siga os procedimentos desse post.

* Todos os links e vídeo aqui mostrado são de seus respectivos autores. Apenas estou divulgando seus artigos já que, se eu escrevesse, seria redundante ;)

Gerando relatórios com o Crystal Reports

O Crystal Reports é um componente que permite a criação de relatórios personalizados de alto nível. Em substituto de relatórios em HTML puro, ele fornece uma assistência inovadora desde a criação até exportação. Para quem utiliza Java, há também uma versão específica para a linguagem. Mostraremos abaixo como gerar um simples relatório buscando dados de uma tabela em banco usando C#.

Abra/Crie um projeto do tipo Web Site no Visual Studio e no Solution Explorer clique com o direito no diretório onde deseja criar o relatório. Escolha Add New Item e opte pelo template Crystal Reports (note que a extensão de relatório do Crystal é .rtp). Nessa primeira tela escolha a primeira opção conforme a figura abaixo:


Clique em OK. Expanda o nó do Create New Connection e novamente expanda o OLE DB (ADO) para configuração de conexão (essa é a primeira conexão com o banco para início, depois mostraremos como usar para outro banco). Na configuração do ADO, escolha o tipo de provider a ser utilizado (no caso optei pelo SQL Server, então SQL Native Client) e dê Next.


Agora, em Connection Information, informe os dados de conexão.


Clique em Next e na última tela revise os dados. Se estiver tudo certo, clique em Finish. Você voltará à tela anterior já com a configuração realizada e o banco estará apto a selecionar os objetos. Procure qual objeto irá ser manipulado e exibido seus dados, podendo ser: uma tabela, um schema, uma view ou stored procedure. Clique no objeto desejado e, em seguida, clique no botão com a seta para direita conforme figura abaixo:


Clique em Next. Agora informe quais campos irão ser exibidos e escolha Next.


Na próxima tela, se precisar agrupar alguns campos, informe quais são. Se não precisar dê apenas Next. Se o Crystal identificar que está trabalhando com números, ele cria um passo adicional que é a opção de inserir gráficos. Outra tela que é exibida é a de Filtros. Se for ter filtros, informe-os. Caso contrário dê apenas Next. Ou seja, as duas últimas telas são parâmetros opcionais logo, se não desejar configurá-los, dê Next duas vezes. O último passo é escolher o estilo. Opte pelo mais parecido que quer e dê Finish.


Basicamente seu relatório está pronto, bastando ajustes da posição dos campos, design, cabeçalho, etc. Em Field Explorer, contêm as principais funcionalidades para fórmulas e cálculos avançados bem como a adição de novos campos. Como estamos elaborando um relatório simples, vamos parar por aí. Para ver um preview de como estará seu relatório com os dados, clique em Main Report Preview. Agora vamos ver como chamar pelo ASP.NET (C#).
Adicione uma página Impressao.aspx e nele adicione um objeto CrystalReportViewer que automaticamente irá ser registrado o assembly na página (puxando do ToolBox ele insere automaticamente). Se preferível configure alguns atributos do objeto como remoção da logo da BO, tema, etc. No code-behind, adicione os seguintes namespaces:

using CrystalDecisions.ReportSource;
using CrystalDecisions.Shared;
using CrystalDecisions.CrystalReports.Engine;
 
E para exibir os dados do relatório utilize o seguinte código:
 
DataSet ds = new DataSet();
// Antes, faço uma consulta no banco e jogo no DataSet para ser usado logo abaixo
ReportDocument relatorio = new ReportDocument();
relatorio.Load(Server.MapPath("Relatorio.rpt"));
relatorio.Database.Tables[0].SetDataSource(ds.Tables[0]);
// Esse é Viewer que puxamos antes
CrystalReportViewerRelatorio.ReportSource = relatorio;
CrystalReportViewerRelatorio.DataBind();
 
Pronto! Seu relatório será exibido...
 
 
Agora vamos aos problemas:
 
1) Fiz todo o processo mas ao exibir o relatório está pedindo login e senha do SQL Server
 
Se estiver usando DataSet, veja que só pude passar uma tabela por vez usando ds.Tables[0] e não apenas ds. Se quiser passar várias tabelas crie um DataSet tipado no App_Code ou informe uma a uma no atributo Database.
 
2) As imagens dos botões do relatório não estão aparecendo e ao clicar não funciona nada
 
Ao ser colocado em produção, verifique se o Crystal Reports está instalado corretamente na máquina. Veja se a pasta wwwroot\aspnet_client\system_web\ contêm a pasta CrystalReportWebFormViewer (depois da pasta system_web vem a versão do framework - exemplo 2_0_50727 - e em seguida vem ela). Copie a pasta aspnet_client e adicione na raiz de sua aplicação.
 
3) Ao exibir o relatório está aparecendo o erro: Não foi possível carregar arquivo ou assembly 'System.Web.Extensions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' ou uma de suas dependências. A definição do manifesto do assembly localizado não corresponde à referência do assembly. (Exceção de HRESULT: 0x80131040)
 
Faça os procedimentos informados nesse post.
 
4) Depois que é exibido o relatório, ao clicar no botão de imprimir ou exportar ou qualquer outro botão, não executa nenhum dos processos que deveria fazer
 
Se estiver usando ASP.NET AJAX e o CrystalReportViewer estiver dentro de um UpdatePanel, remova-o. Pois, ao clicar em desses botões, é feito um PostBack na página (além de tentar abrir uma janela pop-up) e o Crystal não funciona adequadamente quando utiliza o AJAX.
 
5) Ao tentar exibir o relatório, ocorre o seguinte erro: O inicializador de tipo de 'CrystalDecisions.CrystalReports.Engine.ReportDocument' acionou uma exceção
 
Reinstale o Crystal Reports ou tente as soluções sugeridas nesse post.
 
6) Minhas imagens e/ou gráficos não estão aparendo ao exibir o relatório (fica aquele X de imagem não carregada) ou ficam distorcidas/baixa resolução
 
Se for uma imagem que está sendo inserida do disco (que você tem no computador e está inserindo através de Insert > Picture) verifique o formato dessa imagem (preferível JPG ou BMP) e as cores utilizadas bem como efeitos (fundo transparente, camadas). Quanto mais simples a imagem for, melhor será sua visualização. Se apesar de tudo ainda não estiver aparecendo, verifique no web.config se há as seguintes entradas:
  1. Em system.web > httpHandlers:

    <add verb="GET" path="CrystalImageHandler.aspx" type="CrystalDecisions.Web.CrystalImageHandler, CrystalDecisions.Web, Version=10.5.3700.0, Culture=neutral, PublicKeyToken=692fbea5521e1304"/>
    <add verb="*" path="GenerateImage.ashx" type="GenerateDynamicImage"/>
     
  2. E em system.webServer > handlers:

    <add name="CrystalImageHandler.aspx_GET" verb="GET" path="CrystalImageHandler.aspx" type="CrystalDecisions.Web.CrystalImageHandler, CrystalDecisions.Web, Version=10.5.3700.0, Culture=neutral, PublicKeyToken=692fbea5521e1304" preCondition="integratedMode"/>
7) Meu relatório tem mais de 2 páginas mas só fica exibindo 2/2+ quando clico em avançar

Coloque todo o processo de geração do relatório dentro de Page_Init ou invés de Page_Load.

8) Meu relatório não exibe, a princípio, a quantidade total de páginas. Fica exibindo 1/1+...

O Crystal faz isso para não ter de renderizar todo o relatório e sobrecarregar, então faça o seguinte artifício depois de dar o Bind():

CrystalReportViewerRelatorio.ShowLastPage();
CrystalReportViewerRelatorio.ShowFirstPage();

Ou seja, vou rapidamente para a última página e volto apenas para o Crystal renderizar a última página e saber quantas temos ao todo.