Depois de nos matarmos para entender o funcionamento, noites em claro para testes e mais testes, a SEFAZ – Salvador disponibilizou uma DLL e um conjunto de c??digos-fonte para realizar todo o processo de assinatura e envio. Agora ?? m??o na roda para quem ir?? come??ar a implementar. Para quem j?? passou por esse sofrimento agora ?? s?? descan??o… Para mais informa????es acesse aqui. Abaixo tem os links dos principais arquivos para o utilit??rio, documentos e XMLs de exemplo:
Desde que lan??aram a nota fiscal eletr??nica, n??s programadores ficamos com receio do uso das leitoras e cart??es nos sistemas operacionais para a assinatura do XML usando o certificado digital. Geralmente os servidores usufruem de alguma vers??o do Windows Server para acomodar as aplica????es web (que realizam o processo de assinatura) al??m de proporcionar mais robustez e qualidade diante dos trabalhos. Mas as leitoras e cart??es simplesmente n??o funcionam como deveriam! Incompatibilidade… dizem.
Enfim… como fazer? Simplesmente ?? s?? usar outro sistema operacional!
“Mas como vou usar se meu servidor ?? Windows Server e n??o posso instalar outro SO?” (Voc?? se perguntando)
Resposta: Use os dois atrav??s de uma m??quina virtual! H?? v??rios tipos e para v??rios gostos ficando a crit??rio do que voc?? for utilizar. Recomendo o VMware! Ele disp??e de duas vers??es (h?? outras que voc?? pode optar tamb??m) que s??o ??timas para uso: Player e Server. Em resumo, a Player ?? limitada pois seu uso ?? simples mas n??o deixa de ser ??til.
Vamos ao processo que ser?? bem simples:
- Instale uma das vers??es do VMware;
- Instale um Windows 2000/XP/Vista nela contanto que seja compat??vel com sua leitora/cart??o (a instala????o ?? bem simples e sem dificuldades – ?? mais f??cil do que quando vai instalar no computador “de verdade” bastando seguir o Wizard dela);
- Agora conecte a leitora do cart??o no PC. Note que no Windows Server n??o acontecer?? nada, mas no Windows interno come??ar?? a instala????o;
- Em seguida espete o cart??o na leitora;
- Abra o utilit??rio da leitora (atrav??s do Windows da m??quina virtual) e ver?? que o cart??o foi lido corretamente.
Pronto! Da?? basta compartilhar uma pasta entre o Windows Server e a m??quina virtual (atrav??s do VMWare se faz isso) e, enquanto no Windows Server vai jogando os XMLs nessa pasta, o Windows MV (da m??quina virtual) vai assinando/enviando. Bem louco, n??o? Mas funciona! Pode at?? ter o Linux virtualizando um Windows que a leitora ir?? funcionar.
Esses dias me deparei com esse problema. Bem, h?? diversas causas que podem levar a isso e algumas solu????es podem ser facilmente encontradas pela net mostrando problemas:
E in??meros artigos/helps contendo outras solu????es/causas… Mas tamb??m h?? um caso devido ao Application Pool. Resumo: o Application Pool gerencia a mem??ria que ?? utilizada pelas aplica????es no IIS. N??o vou entrar em detalhes e serei bem direto na solu????o.
Post r??pido para redirecionar seu endere??o caso um usu??rio, ao digitar http://thiagomarcal.blogspot.com/, seja redirecionado automaticamente para https://thiagomarcal.blogspot.com/. Adicione um arquivo Global.asax e aplique o seguinte m??todo:
protected void Application_BeginRequest(Object sender, EventArgs e)
{
if (!Request.IsSecureConnection)
{
string endereco = string.Format(“https{0}”, Request.Url.AbsoluteUri.Substring(4));
Response.Redirect(endereco);
}
}
Selecione o TextBox, v?? na guia Properties e clique no ??cone de Events. Adicione um evento em KeyDown conforme a figura abaixo:
{
if (e.KeyCode == Keys.Enter)
{
string entrada = txtNumero.Text;
txtNumero.Text = “”;
}
}
ASP.NET com Banco Firebird
Semelhantemente com o post do MySQL, irei demonstrar como conectar a um banco Firebird usando o Framework (DLL) que eles disponilizam e que pode ser obtido aqui. Vou resumir o processo pois ?? bem parecido, da?? ?? s?? dar uma olhadinha r??pida no post anterior.
Basicamente incorpore a DLL no projeto e crie uma nova classe chamada Firebird. Adicione o namespace FirebirdSql.Data.FirebirdClient e adicione o seguinte c??digo para consulta:
FbConnection conexao = new FbConnection(“String Conex??o Firebird”);
FbCommand comando = new FbCommand();
FbDataReader datareader = null;
try
{
conexao.Open();
try
{
FbTransaction transacao = conexao.BeginTransaction();
comando.Connection = conexao;
comando.CommandText = “SELECT * FROM Tabela”;
datareader = comando.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
transacao.Commit();
}
catch (FbException erro) { }
}
catch (FbException erro) { }
Bem semelhante… nada de novo! Da?? pode-se gerar os demais m??todos de conex??o a partir desse.
Vi em alguns t??picos pela NET que o pessoal encontra alguns problemas ao tentar conectar ao Firebird. O principal erro ??: “Your user name and password are not defined. Ask your database administrator to set up a Firebird login.”
Novamente, vi solu????es muito loucas e esdr??xulas mas que foram tentativas de ajudar e de boa vontade do pessoal. Bem, mesmo que seu login e senha estejam certos (e tenha certeza disso antes de reclamar), o Firebird, em comunica????o com a DLL, n??o d??o muita transpar??ncia e ajuda ao usu??rio. O problema, basicamente, ?? a string de conex??o. Basta usar essa:
User=SYSDBA; Password=masterkey; Database=C:BancosFirebirdThiago.fdb; DataSource=localhost; Port=3050; Dialect=3; Charset=NONE; Role=; Connection lifetime=15; Pooling=true; MinPoolSize=0; MaxPoolSize=50; Packet Size=8192; ServerType=0;
Ou
User=SYSDBA; Password=masterkey; Database=C:BancosFirebirdThiago.fdb; Server=localhost;
Problema resolvido!
Lendo aquele bolo de especifica????o da ABRASF muitos devem perguntar: “Certo, sei quais campos colocar no XML mas qual a ordem do processo de assinatura?”. A documenta????o n??o fica claro realmente como e qual a melhor forma de assinar. Realize a seguinte ordem:
- Gere o XML da Rps e assine;
- Se for enviar mais de uma Rps em um mesmo lote, repita o passo 1 para cada Rps;
- Anexe todas as Rps j?? assinadas no XML do Lote;
- Assine o Lote e fa??a o envio.
Seu XML de envio deve ficar semelhante ?? figura abaixo:
Para fazer a assinatura dos XMLs, utilize a fun????o abaixo:
private XmlDocument AplicaAssinatura(string xml, string uri)
{
try
{
// Obtem o certificado
X509Certificate2 X509Cert = ObtemCertificado();
// Cria um documento XML para carregar o XML
XmlDocument docXML = new XmlDocument();
docXML.PreserveWhitespace = true;
// Carrega o documento XML
docXML.LoadXml(xml);
// Cria o objeto XML assinado
SignedXml signedXml = new SignedXml(docXML);
// Assina com a chave privada
signedXml.SigningKey = X509Cert.PrivateKey;
// Atribui o m??todo de canoniza????o
signedXml.SignedInfo.CanonicalizationMethod = “http://www.w3.org/TR/2001/REC-xml-c14n-20010315”;
// Atribui o m??todo para assinatura
signedXml.SignedInfo.SignatureMethod = “http://www.w3.org/2000/09/xmldsig#rsa-sha1”;
// Cria a referencia
Reference reference = new Reference();
// Pega a URI para ser assinada
XmlAttributeCollection _Uri = docXML.GetElementsByTagName(uri).Item(0).Attributes;
foreach (XmlAttribute _atributo in _Uri)
{
if (_atributo.Name == “id”)
reference.Uri = “#” + _atributo.InnerText;
}
// Adiciona o envelope ?? refer??ncia
XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
reference.AddTransform(env);
// Atribui o m??todo do Hash
reference.DigestMethod = “http://www.w3.org/2000/09/xmldsig#sha1”;
// Adiciona a referencia ao XML assinado
signedXml.AddReference(reference);
// Cria o objeto keyInfo
KeyInfo keyInfo = new KeyInfo();
// Carrega a informa????o da KeyInfo
KeyInfoClause rsaKeyVal = new RSAKeyValue((System.Security.Cryptography.RSA)X509Cert.PrivateKey);
KeyInfoX509Data x509Data = new KeyInfoX509Data(X509Cert);
x509Data.AddSubjectName(X509Cert.SubjectName.Name.ToString());
keyInfo.AddClause(x509Data);
keyInfo.AddClause(rsaKeyVal);
// Adiciona a KeyInfo
signedXml.KeyInfo = keyInfo;
// Atribui uma ID ?? assinatura
signedXml.Signature.Id = “Assigned” + uri;
// Efetiva a assinatura
signedXml.ComputeSignature();
// Obtem o XML assinado
XmlElement xmlDigitalSignature = signedXml.GetXml();
// Adiciona o elemento assinado ao XML
docXML.DocumentElement.AppendChild(docXML.ImportNode(xmlDigitalSignature, true));
// Retorna o XML
return docXML;
}
catch (Exception erro) { throw erro; }
}
O par??metro URI ?? o nome da tag geral que deve ser assinada de um XML, no caso dever?? assinar as tags InfRps (cada uma) e LoteRps. A fun????o ObtemCertificado j?? foi exibida aqui em um t??pico anterior que serve para captura do certificado digital.
Depois de muito tempo voltei a escrever alguns artigos. Pouco tempo dispon??vel e algumas prioridades… Bem, esse t??pico, apesar de simples, ?? de bem ajuda para que desejar gerar RSS dinamicamente. O c??digo ?? bem simples: apenas Response!
Crie uma p??gina que ir?? exibir o RSS e coloque o seguinte c??digo no Page_Load:
StringBuilder rss = new StringBuilder();
rss.AppendLine(“<rss version=”2.0″>”);
rss.AppendLine(“<channel>”);
rss.AppendLine(“<title>Thiago Mar??al</title>”);
rss.AppendLine(“<link>http://thiagomarcal.blogspot.com/</link>”);
rss.AppendLine(“<description>Blog que compartilha id??ias e c??digo-fontes ?? comunidade.</description>”);
rss.AppendLine(“<language>pt-br</language>”);
SqlDataReader dr = consulta(“SELECT * “);
while (dr.Read())
{
rss.AppendLine(“<item>”);
rss.AppendLine(“<title>” + Funcoes.RemoveHTML(Server.HtmlDecode(dr[“titulo”].ToString())) + “</title>”);
rss.AppendLine(“<description>” + Funcoes.RemoveHTML(Server.HtmlDecode(dr[“texto”].ToString())) + “</description>”);
rss.AppendLine(“<link>” + dr[“link”].ToString() + “</link>”);
rss.AppendLine(“<pubDate>” + DateTime.Parse(dr[“data”].ToString()).ToString(“dd/MM/yyyy HH:mm:ss”) + “</pubDate>”);
rss.AppendLine(“</item>”);
}
rss.AppendLine(“</channel>”);
rss.AppendLine(“</rss>”);
dr.Close();
Response.ContentType = “text/xml”;
Response.Write(rss.ToString());
Bem simples, n??o? O m??todo Funcoes.RemoveHTML remove qualquer tag HTML que contenha na string. Eu criei uma bem simples baseada em express??o regular. Voc?? pode criar a seu gosto…
Apesar do t??tulo grande e, para uns, confuso, nesse t??pico irei ajudar muitos a resolver um problema: m??ltiplos uploads de vez sem precisar selecionar cada arquivo.
A id??ia primordial ?? fazer com que o usu??rio possa clicar em um bot??o, selecionar v??rios arquivos de vez (que nem o GMail) e fazer o envio para uma pasta desejada. Para isso iremos utilizar um Handler em C# para fazer o upload. Mas nesse mesmo Handler irei escrever na sess??o para que possa utilizar em outra p??gina. Lembrando que as vari??veis de sess??o, para usar dentro de um Handler precisa-se de um artif??cio. Sem mais delongas, vamos ?? solu????o.
Crie ou abra um Web Site Project e nele adicione um Generic Handler. Coloque com o nome Upload.ashx para ficar mais f??cil de encontr??-lo. Insira o seguinte c??gido:
using System;
using System.Data;
using System.IO;
using System.Web;
using System.Web.SessionState;
public class Upload : IHttpHandler, IRequiresSessionState{
public void ProcessRequest (HttpContext context) {
context.Response.ContentType = “text/plain”;
context.Response.Expires = -1;
try
{
// Obt??m o arquivo a ser postado
HttpPostedFile postedFile = context.Request.Files[“filedata”];
// Caminho
string path = context.Server.MapPath(“~/Upload/”);
string filename = postedFile.FileName;
// Cria diret??rio de n??o existir
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
// Verifica se o arquivo j?? existe com mesmo nome
string nome = filename.Substring(0, filename.LastIndexOf(“.”));
string extensao = filename.Substring(filename.LastIndexOf(“.”) + 1);
int i = 1;
// Verifica se existe, sen??o renomeia
while (File.Exists(path + @”” + filename))
{
filename = nome + “(“ + i + “).” + extensao;
i++;
}
// Adiciona na sess??o
DataTable galeria = (DataTable)context.Session[“galeria”];
DataRow item = galeria.NewRow();
item[“imagem”] = filename;
galeria.Rows.Add(item);
context.Session[“galeria”] = galeria;
// Salva arquivo
postedFile.SaveAs(path + @”” + filename);
// Retorna o arquivo salvo
context.Response.Write(path + “/” + filename);
context.Response.StatusCode = 200;
}
catch (Exception ex)
{
context.Response.Write(“Erro: “ + ex.Message);
}
}
public bool IsReusable {
get {
return true;
}
}
}
Pronto! J?? temos nosso Handler que faz o upload de um arquivo e o adiciona em um DataTable. Esse DataTable j?? estava previamente adicionado na sess??o. Voc?? pode utilizar quaisquer outra estrutura para armazenar. A dica da escrita na sess??o no Handler est?? na heran??a da interface IRequiresSessionState onde permitir?? fazer isso.
Crie uma p??gina ASPX e referencie os JavaScripts do JQuery abaixo (os arquivos, caso n??o possuam, irei disponibilizar em um link abaixo) e um CSS pra dar um estilo legal:
<link rel=”stylesheet” type=”text/css” href=”css/stilo.css” />
<script type=”text/javascript” src=”js/jquery-1.3.2.min.js”></script>
<script type=”text/javascript” src=”js/jquery.uploadify.js”></script>
Agora adicione um controle FileUpload e um link (ou um controle HyperLink). Iremos tamb??m fazer a chamada do JQuery para ser aplicado sobre o FileUpload ficando dessa forma:
<asp:FileUpload ID=”Fotos” runat=”server” />
<input type=”button” onclick=”javascript:$(‘#<%=Fotos.ClientID%>‘).fileUploadStart();” value=”Enviar” />
<script type=”text/javascript”>
$(window).load(
function() {
$(“#<%=Fotos.ClientID %>”).fileUpload({
‘uploader’: ‘js/uploader.swf’,
‘cancelImg’: ‘imagens/cancelar.png’,
‘buttonText’: ‘Selecionar’,
‘script’: ‘Upload.ashx’,
‘folder’: ‘Upload’,
‘fileDesc’: ‘Selecione arquivos do tipo imagem’,
‘fileExt’: ‘*.jpg;*.jpeg;*.gif;*.png’,
‘multi’: true,
‘auto’: false
});
}
);
</script>
Agora rode a aplica????o. Ver?? apenas um bot??o com o nome Selecionar. Ao clicar ir?? abrir um pop-up pedindo para selecionar os arquivos. Selecione um ou mais e clique em OK. Ver?? que ser?? montado uma lista com os arquivos que ir??o ser enviados. Voc?? poder?? remover itens clicando no X sobre cada um deles. Ao clicar no link Enviar, ser?? feito uma chamada para cada item sobre o Handler fazendo o envio para a pasta Upload e adicionando no DataTable armazenado na sess??o.
N??o vou entrar muito em datelhes, porque est?? bem f??cil e compreens??vel o c??digo. Se desejar, ao inv??s de clicar em Enviar para fazer o envio, voc?? pode deixar autom??tico (como se fosse uma trigger) mudando o par??metro ‘auto’ para true da chamada JQuery. Ent??o, ao selecionar e clicar em OK automaticamente ser?? feito o upload. Se tamb??m quiser que o link fa??a um PostBack na p??gina, basta colocar depois da chamada de in??cio do upload, insira o __doPostBack(”,”); colocando par??metro ou n??o dependendo do que for fazer com ele ap??s.
Nesse link aqui encontram-se alguns arquivos necess??rios para que possam utilizar. N??o vou colocar os fontes ASP.NET porque sen??o j?? seria demais, n??? M??os ?? obra…
Obs: a fonte e outras mat??rias sobre o mesmo t??pico voc?? acha a?? pela net. N??o me lembro qual site eu havia visto algo do tipo e fiz essa. Mas fica a dica a??!
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.