Obter Certificado Digital para Nota Fiscal Eletrônica

Post rápido sobre Nota Fiscal Eletrônica... Caso esteja desenvolvendo a aplicação de NFe para um PF e/ou PJ e esteja utilizando certificados do tipo A3 (no A1 deve servir também, mas ainda não testei), utilize a função abaixo para capturar da leitora o certificado. Os dados são armazenados no objeto para posterior manipulação, exemplo, assinatura do XML para envio.

using System.Security.Cryptography.X509Certificates;

X509Certificate2 oX509Cert = new X509Certificate2();
X509Store store = new X509Store("MY", StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
X509Certificate2Collection collection1 = (X509Certificate2Collection)collection.Find(X509FindType.FindByTimeValid, DateTime.Now, false);
X509Certificate2Collection collection2 = (X509Certificate2Collection)collection.Find(X509FindType.FindByKeyUsage, X509KeyUsageFlags.DigitalSignature, false);
X509Certificate2Collection scollection = (X509Certificate2Collection)collection2.Find(X509FindType.FindBySubjectName, "NOME DA EMPRESA \ PESSOA", false);
if (scollection.Count == 0)
    oX509Cert = null;
else
    oX509Cert = scollection[0];
 
No objeto oX509Cert é o objeto representativo de seu certificado digital no seu sistema. Geralmente esse tipo de certificado fica armazenado temporariamente na pasta Pessoal do Gerenciador de Certificados do Windows. Caso deseje visualizar qual o nome correto do certificado e realizar demais operações, vá em Iniciar, Executar e digite certmgr.msc. Uma tela como essa irá surgir:
 

Se o seu certificado não aparecer aí, deve ser que o leitor não está reconhecendo o cartão, ou o software de leitura não foi corretamente instalado e outros fatores que agora não entrará em detalhes.

SqlDataSource e MySQL

Estava fazendo uma integração de bases de dados MySQL e SQL Server e, em certa etapa, teria que utilizar o SqlDataSource para preencher um GridView alternando entre o SQL Server e o MySQL. Contudo, nativamente, o provider do SqlDataSource não aceita o MySQL a não ser por ODBC conforme especificação. Dei uma lida na net para ver alguns comentários e ví alguns absurdos como: "o SqlDataSource é específico do SQL Server" entre outros. Parece que o pessoal não lê as especificações. Como disse, dá sim, mas por ODBC. Mas usando o conector MySQL, conforme um post anterior, é possível realizar a integração do SqlDataSource a uma base MySQL sem ser por ODBC usando o conector específico. Vamos por a mão na massa...

Primeiramente vá no web.config e adicione as seguintes configurações:

<system.data>
<DbProviderFactories>
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description="Conector .NET para o MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.2.2.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
</DbProviderFactories>
</system.data>

Atente-se à versão da DLL do conector que está utilizando. No caso, estou usando a 6.2.2.0. Aplique também o Assembly inserindo a tag abaixo:

<add assembly="MySql.Data, Version=6.2.2.0, Culture=neutral, PublicKeyToken=C5687FC88969C44D" />

Como disse, não vou entrar em detalhes, mas adicionando essas configurações no web.config de seu projeto já estará apto para trabalhar adequadamente com o MySQL. Agora  o resto é simples, basta inserir o SqlDataSource e colocar o ProviderName="MySql.Data.MySqlClient".

Obs: Não coloque nenhum driver no ConnectionString do SqlDataSource como "Driver=MySQL ODBC 3.5;" ou suas variantes. Utilize a string de conexão convencional, pois o provider irá fornecer informações específicas para que o objeto possa se conectar normalmente.

ASP.NET com Banco MySQL

Todos viram aqui que meus posts dispensam muito embasamento teórico e parte logo para a prática. Gosto de ser direto... então, vamos lá! Para conectar a bancos MySQL podemos utilizar o ODBC do .NET para conectar e realizar consultas a ele. Contudo, esse tipo de conexão é mais lento e não usurfrui de conjunto de instruções específicas que podem otimizar as operações sobre o banco de dados, exemplo o namespace System.Data.SqlClient no qual possuem instruções específicas do SQL Server para manipulações dos dados. Assim sendo, a própria MySQL disponibilizou um conector específico para programação .NET. Para isso, pode realizar o download aqui.

Faça o download do instalador ou zip para obtermos as DLLs. Caso tenham dificuldade na obtenção dos arquivos, vejam nesse link aqui onde contêm apenas as DLLs básicas para o funcionamento. Com os arquivos em mãos, insira-os na pasta Bin do projeto ou dê um Add Reference para incorporá-las. Com as DLLs no seu devido local, as classes MySQL já podem ser acessadas quando adicionado o namespace MySql.Data.MySqlClient. Abaixo, temos um exemplo de realizar uma consulta no banco de dados. Nota-se que se assemelha bastanto com o SqlDataReader, OdbcDataReader, etc:

using MySql.Data.MySqlClient;

MySqlConnection conexao = new MySqlConnection("String Conexão MySQL");
MySqlCommand comando = new MySqlCommand();
MySqlDataReader datareader = null;
try
{
    conexao.Open();
    try
    {
        comando.Connection = conexao;
        comando.CommandText = "SELECT * FROM Tabela";
        datareader = comando.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
    }
    catch (MySqlException erro) { }
}
catch (MySqlException erro) { }

O objeto MySqlDataReader contêm os dados da consulta efetuada. Bem similiar com as outras formas de uso de conexão, então não há erro. Parameters, DataSet e muitos métodos que o conector fornece podem ser usados de forma similar aos demais conectores citados anteriormente. Fácil...

Então é isso! Caso tenham dificuldade na string de conexão para o MySQL veja no ConnectionStrings a mais adequada a sua necessidade.

"Crash" nos Templates do Visual Studio - Parte 2

Quem leu o primeiro post do "Crash" de Templates do Visual Studio deve ter visto que esse não foi o erro que aconteceu comigo (você que está lendo, digo)... Outro erro tem assombrado programadores quando é emitido uma mensagem como essa:
"Package 'Visual Web Developer HTML Source Editor Package' has failed to load properly ( GUID = {BFCC0C3C-6F87-4285-A6C8-BB616061800D} ). Please contact package vendor for assistance. Application restart is recommended, due to possible environment corruption. Would you like to disable loading this package in the future? You may use 'devenv /resetskippkgs' to re-enable package loading."
Essa e suas variantes ficam informando esse erro e pedindo para executar o comando devenv /resetskippkgs para reabilitar os pacotes de volta. Muito bem, eu já havia ensinado em um post anterior como realizar a execução desse tipo de comando. Mas supondo que você executou o procedimento, abre de novo o Visual Studio e o erro persiste... e agora?
 
Bem, provavelmente você irá fazer algumas das sugestões recomendadas anteriormente, contudo descobri o seguinte: algumas instalações fazem com que a linguagem do Visual Studio fique em português (perceba se a aplicação está com o menu ou partes em português), por exemplo, quando feito a instalação de algum Add-on, e faz com que aconteça esse tipo de crash.
 
O Visual Studio não trabalha bem com outro tipo de linguagem a não ser o inglês devido a variantes que ele possui bem como o funcionamento dos controle e reconhecimento do parse da linguagem. Então, devemos colocar o Visual Studio de volta para a linguagem padrão e para isso realize os seguintes passos:
  1. Abra o Visual Studio;
  2. Entre em Tools e em seguida escolha Options;
  3. Caso todas as opções não estejam sendo exibidas, clique em "Show all settings";
  4. Em Environment e escolha o item International Settings;
  5. Selecione a linguagem Inglês (English) e clique em OK;
  6. Feche o Visual Studio;
  7. Execute o comando devenv /resetskippkgs conforme explicado anteriormente.
Com isso, o problema já estará corrigido. Ai você diz: "Mas as opções você escreveu em Inglês? E no meu aparece em Português...". Mais fácil do que isso é impossível! Google está aí pra isso... Boa sorte!

Reduzir Log SQL Server

Nesse primeiro post sobre SQL Server vou explicar como reduzir o log do SQL Server 2005 e 2008. No log contêm as instruções que foram executadas ultimamente no banco de dados. Para quem trabalha com recuperação em log pode preferir manter o log por algum período antes de fazer uma redução. Mas para outros bancos de dados que realizam inserções e atualizações constantes pode ficar inviável manter o log por grandes períodos devido a prover um crescimento exarcebado. Bem isso você pode ver melhor a depender da política de backup que você for utilizar. Considerando que o log para você não tem importância de mantê-lo por muito tempo e não quer mexer nas configurações no SQL Server, essa é uma boa dica de fazer a redução através de comandos SQL.

Pelo próprio SQL Server Management Studio você pode utilizar da função Shrink e fazer a redução do banco de dados e log. Muitas vezes a redução (vamos nos atentar ao do log) chega a ser pouca pois ele mantêm ainda algumas das instruções mais recentes. Mas para forçosamente realizar a redução execute a seguinte intrução:

SQL Server 2005
USE Banco_Dados
GO
BACKUP LOG Banco_Dados WITH TRUNCATE_ONLY
DBCC SHRINKFILE (Banco_Dados_log, 1)

SQL Server 2008
USE Banco_Dados;
GO
ALTER DATABASE Banco_Dados
SET RECOVERY SIMPLE;
GO
DBCC SHRINKFILE (Banco_Dados_Log, 1);
GO
ALTER DATABASE Banco_Dados
SET RECOVERY FULL;
GO
 
Ambos os procedimentos fazem com que o log seja reduzido a 1Mb. Nota-se que a instrução de redução é a mesma. A única diferença é que para realizar a trucamento, no 2005 é preciso informar que o backup de log será truncado explicitamente e no 2008 deve mudar o status para recuperação simples antes de truncá-lo. Se quiser realizar o truncamento automático de todos os bancos do servidor basta fazer um SELECT com cursor sobre todos os bancos pegando o name deles e executando o script acima. Mas isso deixarei para mostrar outro dia...

"Crash" nos Templates do Visual Studio

Ontem, quando estava instalando um componente no Visual Studio, tudo funcionava normalmente como um dia qualquer. Não me esperava o Visual Studio falhar na hora que mais precisava dele. Ao trabalhar em um projeto e adicionar um novo item, todos os templates sumiram!!! Não podia selecionar nenhum template (óbvio que não poderia criar mais nada) e ao mesmo tempo surgia-se um erro bizarro informando para que eu entrasse no visualizador de eventos para obter com mais detalhes.

Chegando lá aparecia um erro informando que houve uma falha no carregamento dos templates e que era para executar o comando abaixo para fazer uma recuperação dos templates:

devenv.exe /installvstemplates

Para executar o comando, vá em Iniciar, depois em Programas escolha a pasta do Microsoft Visual Studio 2008/2005, depois na Visual Studio Tools e clique no prompt Visual Studio 2008/2005 Command Prompt. Entre com o comando descrito acima e dê Enter. Aparentemente o comando é executado sem problemas e rapidamente. Só que tem uma coisa: volte a abrir o Visualizador de Eventos (para quem não sabe o Visualizador de Eventos encontra-se no Painel de Controle - Ferramentas Administrativas) e monitore os eventos que estão sendo gerados. Espere um instante e veja se nenhuma entrada foi gerada. Se der tudo certo, no máximo, irá surgir alguns warnings no log mas que pouco afeta a restauração.

E, por mais que queremos, uma coisa nunca funciona na primeira vez. Logo que executei apareceu inúmeros erros (nem eram warnings). Abri o Visual Studio e continuava a mesma coisa. Li alguns materiais na Internet e notei que algumas pessoas já se depararam com esse problema. Encontrei vários métodos para lidar com a situação, mas pensei melhor e fiquei com receio de piorar o que já estava estragado. Então fiz o que todo brasileiro gosta de fazer: tentar de novo! Executei o mesmo processo e funcionou! Aparentemente estava tudo de volta...

Obs: Feche todas as instâncias do Visual Studio senão não funciona corretamente.

Para quem tiver essa sorte, verifique se está tudo nos conformes. Quem não conseguiu recomendo fortemente reinstalar o Visual Studio novamente. Senão, tente alguns dos tutoriais espalhados pela net. Alguns procedimentos como os descritos abaixo podem ajudar caso não resolva baseando-se nos métodos acima:
  1. Mudar o diretório dos templates na configuração do Visual Studio;
  2. Verifique se os templates necessários existem na pasta "C:\Program Files\Microsoft Visual Studio 9\Common7\IDE\ProjectTemplates" e "ItemTemplates"
Outra solução drástica é fazer a restauração do sistema para um ponto onde estava funcionando corretamente a aplicação. Boa sorte!

Utilizando CAPTCHA para validação

Creio que todo mundo já passou por alguma validação de formulário na qual precisava digitar um código que é exibido em uma imagem para que a validação ocorra "adequadamente" (digamos por um usuário e não por um robô). Um utilitário que expandiu drasticamente pela web e uso quase que comum pela comunidade é do reCAPTCHA. Muito fácil de utilizar, ele já fornece DLL/Implementações para algumas linguagens tais como o PHP, .NET, Wordpress e outros. Nesse caso, vamos nos atentar ao plugin do ASP.NET. Nesse link contém informações de como proceder e utilizar o plugin.


O processo consiste basicamente na download da DLL, incorporação dela no projeto através inserindo-a na pasta Bin ou dando Add Reference. Na página a ser utilizada, incorpore o código de registro dela e assim pode-se utilizá-la.

Antes de utilizá-la, deve-se gerar uma chave pública e privada para que se processe a criptografia dos dados. Para gerar, você deve se cadastrar aqui e preenche o formulário até que, ao final, seja exibida as chaves. Sem as chaves, o CAPTCHA não funciona.

Então você terá o seguinte código (semelhante):

<%@ Register Assembly="Recaptcha" Namespace="Recaptcha" TagPrefix="recaptcha" %>

<recaptcha:RecaptchaControl ID="recaptcha" runat="server" PublicKey="chavepublica" PrivateKey="chaveprivada" />

Para realizar a validação, deve apenas analisar a seguinte propriedade no PostBack:

recaptcha.IsValid

Na qual irá retornar um booleano se digitou os caracteres corretamente ou não.

Pronto! Basicamente você já está apto a utilizar o CAPTCHA para validar as entradas em seu web-site. Muito bom a utilização, contudo há dois problemas que vi muitas pessoas tendo: utilizar em Português e no AJAX.

Quando você obtêm a DLL não há uma forma de configurar para o português. Para fazer isso você deve obter o projeto da DLL no Source Project deles, abrir e setar manualmente a linguagem ou criar um método público para que faça isso a nível de utilização.

Baixe através do SVN ou via HTTP uma das versões para ASP.NET. Abra o projeto e entre no arquivo RecaptchaControl.cs e procure o método protected override void RenderContents(HtmlTextWriter output). Após a linha output.WriteLine("theme : '{0}',", this.theme ?? string.Empty); insira a seguinte linha:

output.WriteLine("lang : '{0}',", this.lang ?? "pt");

Ainda não compile. No região de declaração de variáveis (em #region Private Fields), insira a variável:

private string lang;

E nas propriedades (em #region Public Properties) insira o método:

[Category("Settings")]
[Description("Configura a linguagem para a desejada.")]
public string Linguagem
{
get { return this.lang; }
set { this.lang = value; }
}

Pronto! Agora compile o projeto e terá uma nova DLL preparada para indicar qualquer linguagem que o reCAPTCHA suporta. Volte ao seu projeto e atualize a referência da DLL para essa nova.

Agora, quando você está utilizando o ASP.NET AJAX juntamente com um UpdatePanel, ao realizar um PostBack, o reCAPTCHA some/desaparece e não é recarregado. O que fazer?

Bem, é fácil! Crie um UpdatePanel para o CAPTCHA exclusivamente. Deixe apenas o CAPTCHA dentro do ContentTemplate e coloque os atributos ChildrenAsTriggers="true" e UpdateMode="Conditional" no UpdatePanel. Agora insira quantas triggers forem precisas dos controles nos quais fazem PostBack nessa página. Ou seja, se houver um DropDownList ou um Button ou qualquer item que faça PostBack na página, eles devem ser inseridos aqui para que o CAPTCHA possa ser carregado caso um deles faça requisição ao servidor.

Seu código ficará parecido dessa forma:

<asp:UpdatePanel ID="PainelCaptcha" runat="server" ChildrenAsTriggers="true" UpdateMode="Conditional">
<ContentTemplate>
<recaptcha:RecaptchaControl ID="recaptcha" runat="server" PublicKey="chavepublica" PrivateKey="chaveprivada" />
</ContentTemplate>
<Triggers>
<asp:PostBackTrigger ControlID="BotaoValidacao" />
</Triggers>
</asp:UpdatePanel>

Problemas resolvidos!