O Mootools é um framework JavaScript para criar abas com um belo design e praticidade no uso. Porém verifiquei que ele tem um certo "probleminha de comportamento" quando o usa dentro de um frame / frameset no IE. O seu carregamento / aplicação de estilo se dá através de uma adição de uma função chamadora na janela (usando window.addEvent). A condição para execução do script se dá quando o DOM estiver pronto, ou seja, window.addEvent('domready',function({})); . O problema é que, para o Internet Explorer (IE) o carregamento da página é meio que desordenado enquanto o Firefox e Chrome (não testei nos demais navegadores) possuem uma ótima engine de carregamento de página. Ou seja, à vezes o conteúdo da página demora a ser carregado e o DOM fica pronto antes dos controles HTML serem devidamente carregados ocasionando erro na execução. Para contornar o problema, basta substituir o 'domready' por 'load'. Então a aplicação do Mootools sobre o conteúdo será providenciado logo que a página for totalmente carregada. O problema é se houver muito conteúdo na página e houver demora no carregamento da página pois o estilo será aplicado apenas no final... daí é só ter mesmo paciência (ou remove do frame)!
Obs: outros frameworks JavaScript podem vir a ocasionar o mesmo problema sob as mesmas circunstâncias.
Problema do Mootools dentro de um frame
Postado por
Thiago Marçal
on domingo, 15 de agosto de 2010
/
Marcadores:
dicas,
javascript,
jquery,
mootools
/
Comments: (1)
Problema no uso de memória no SQL Server 2008
Se em algum momento, quando em trabalho, estiver recebendo uma das seguintes mensagens abaixo, você está tendo sérios problemas de uso de memória:
Isso ocorre quando há várias instruções SQL sendo executadas em seqüência. Como o pool não aguenta, os dados, em algumas vezes, podem travar... Mesmo que fisicamente eles estejam lá, não se pode mais ser utilizados até que o banco seja reiniciado. Para corrigir esse problema há duas formas: instalar o hotfix que a Microsoft disponibilizou ou reduzir quantidade de instruções a serem executadas por vez.
1) Instalar o HotFix
O arquivo está disponível em um pack cumulativo pós SP1 do SQL Server 2008. Para mais informações e download, clique aqui.
2) Reduzir a quantidade de instruções SQL
Fazendo um teste de vários UPDATE's seguidos, consegui obter tal erro. Gerei um arquivo .sql com quase 100mil updates e mandei o SQL Server executar, daí obtive o erro. Nunca tente isso! Se desejar executar vários UPDATE's ou INSERT's de vez fragmente a execução das instruções em blocos (nem tão grandes e nem tão pequenos) dando uma pausa entre as execuções. Pode-se utilizar uma Store Procedure buscando os dados em um tabela temporária e executar a instrução de forma genérica (INSERT com SELECT, por exemplo). Também pode-se usar um artifício do ASP.NET, Batch Update, para executar a instrução de forma genérica com alto desempenho.
* A depender da configuração do SQL Server, ao invés de ser o recurso interno (ou internal) pode ser o recurso default.
"There is insufficient system memory in resource pool 'internal' to run this query" *
ou
"Há memória de sistema insuficiente no pool de recursos internos para executar essa consulta" *
Isso ocorre quando há várias instruções SQL sendo executadas em seqüência. Como o pool não aguenta, os dados, em algumas vezes, podem travar... Mesmo que fisicamente eles estejam lá, não se pode mais ser utilizados até que o banco seja reiniciado. Para corrigir esse problema há duas formas: instalar o hotfix que a Microsoft disponibilizou ou reduzir quantidade de instruções a serem executadas por vez.
1) Instalar o HotFix
O arquivo está disponível em um pack cumulativo pós SP1 do SQL Server 2008. Para mais informações e download, clique aqui.
2) Reduzir a quantidade de instruções SQL
Fazendo um teste de vários UPDATE's seguidos, consegui obter tal erro. Gerei um arquivo .sql com quase 100mil updates e mandei o SQL Server executar, daí obtive o erro. Nunca tente isso! Se desejar executar vários UPDATE's ou INSERT's de vez fragmente a execução das instruções em blocos (nem tão grandes e nem tão pequenos) dando uma pausa entre as execuções. Pode-se utilizar uma Store Procedure buscando os dados em um tabela temporária e executar a instrução de forma genérica (INSERT com SELECT, por exemplo). Também pode-se usar um artifício do ASP.NET, Batch Update, para executar a instrução de forma genérica com alto desempenho.
* A depender da configuração do SQL Server, ao invés de ser o recurso interno (ou internal) pode ser o recurso default.
Gerando Gráficos em ASP.NET
Um componente que gosto de utilizar para gerar gráficos é o FusionCharts. Através dele é possível criar gráficos animados e interativos em Flash como gráficos em pizza, barra, colunas, funil, linha, área, bolha, etc. Além de trabalhar com ASP, ASP.NET, PHP, JSP, ColdFusion, Ruby on Rails, Python e HTML puro, pode-se utilizar em conjunto com bancos de dados como SQL Server, Oracle, MySQL, PostgreSQL, etc... O seu funcionamento consiste em apenas gerar o XML (em tempo de execução ou não) e indicar qual o gráfico. Vamos à prática...
Acesse o site da FusionCharts e baixe o pacote com os gráficos (na versão trial vem apenas os gráficos comuns - os mais complexos vem na versão paga). No arquivo baixado vem os SWF's dos gráficos, exemplos de XML's a serem gerados para cada gráficos, o JavaScript a ser incorporado na página e demais documentos (qualquer dúvida veja na pasta Code > CSNET que contêm um exemplo em ASP.NET e contêm todos os arquivos que irá precisar). Para nosso exemplo, vamos gerar um gráfico em pizza.
Crie um Web Site e adicione as pastas conforme a estrutura abaixo:
Adicione no App_Code as classes Util.cs e DbConn.cs. Na Bin adicione a referência à DLL da FusionCharts.dll, na Graficos adicione o SWF do gráfico que iremos gerar (no caso escolha o Pizza3D.swf) e na pasta Js adicione o FusionCharts.js. Todos esses arquivos são encontrados no ZIP que baixou no mesmo caminho dito anteriormente.
Adicione uma página ASPX agora e adicione no body ou no head o script:
<script language="Javascript" type="text/javascript" src="js/FusionCharts.js"></script>
Também adicione um Literal (Controle) no local onde deverá surgir o gráfico. Para fins didáticos coloque o ID do controle como GraphPizza. Agora tudo será no Code-Behind... Adicione os namespaces Utilities e InfoSoftGlobal usando a cláusula using. Em seguida criamos um método onde é gerado o XML e encapsulado sobre o SWF da seguinte forma:
public void CriarGraficoPizza3D()
{
string strXML = "<graph showNames='1' caption='Tipos de Clientes' decimalPrecision='0'>";
strXML += "<set name='Alvos' value='10' color='ED1C24'/>";
strXML += "<set name='Prospects' value='5' color='FFFF00'/>";
strXML += "<set name='Clientes' value='2' color='00E600'/>";
strXML += "</graph>";
GraphPizza.Text = FusionCharts.RenderChart("Graficos/Pizza3D.swf", "", strXML, "GraficoPizza3D", "400", "300", false, false);
}
No caso, gero todo o XML contendo os dados a serem apresentados e o passo por parâmetro ao método do FusionCharts para renderizá-lo e exibi-lo. Bem simples, não? Esse é o exemplo mais fácil... Há várias formas de apresentá-lo bem como suas opções fazem com que apresente mais variantes. O mais difícil (quer dizer trabalhoso) é gerar o XML...
Acesse o site da FusionCharts e baixe o pacote com os gráficos (na versão trial vem apenas os gráficos comuns - os mais complexos vem na versão paga). No arquivo baixado vem os SWF's dos gráficos, exemplos de XML's a serem gerados para cada gráficos, o JavaScript a ser incorporado na página e demais documentos (qualquer dúvida veja na pasta Code > CSNET que contêm um exemplo em ASP.NET e contêm todos os arquivos que irá precisar). Para nosso exemplo, vamos gerar um gráfico em pizza.
Crie um Web Site e adicione as pastas conforme a estrutura abaixo:
Adicione no App_Code as classes Util.cs e DbConn.cs. Na Bin adicione a referência à DLL da FusionCharts.dll, na Graficos adicione o SWF do gráfico que iremos gerar (no caso escolha o Pizza3D.swf) e na pasta Js adicione o FusionCharts.js. Todos esses arquivos são encontrados no ZIP que baixou no mesmo caminho dito anteriormente.
Adicione uma página ASPX agora e adicione no body ou no head o script:
<script language="Javascript" type="text/javascript" src="js/FusionCharts.js"></script>
Também adicione um Literal (Controle) no local onde deverá surgir o gráfico. Para fins didáticos coloque o ID do controle como GraphPizza. Agora tudo será no Code-Behind... Adicione os namespaces Utilities e InfoSoftGlobal usando a cláusula using. Em seguida criamos um método onde é gerado o XML e encapsulado sobre o SWF da seguinte forma:
public void CriarGraficoPizza3D()
{
string strXML = "<graph showNames='1' caption='Tipos de Clientes' decimalPrecision='0'>";
strXML += "<set name='Alvos' value='10' color='ED1C24'/>";
strXML += "<set name='Prospects' value='5' color='FFFF00'/>";
strXML += "<set name='Clientes' value='2' color='00E600'/>";
strXML += "</graph>";
GraphPizza.Text = FusionCharts.RenderChart("Graficos/Pizza3D.swf", "", strXML, "GraficoPizza3D", "400", "300", false, false);
}
No caso, gero todo o XML contendo os dados a serem apresentados e o passo por parâmetro ao método do FusionCharts para renderizá-lo e exibi-lo. Bem simples, não? Esse é o exemplo mais fácil... Há várias formas de apresentá-lo bem como suas opções fazem com que apresente mais variantes. O mais difícil (quer dizer trabalhoso) é gerar o XML...
Corrigindo dois erros em uma tacada só: O provedor “Microsoft.Jet.OLEDB.4.0” não está registrado na máquina local e O inicializador de tipo de 'CrystalDecisions.CrystalReports.Engine.ReportDocument' acionou uma exceção.
Problema: Porque o sistema operacional é 64bits.
Solução: Modo de compatibilidade em 32bits.
Bom se todo post fosse assim tão rápido para solucionar nossos problemas. Agora vamos alongar mais as respostas e enriquecer nosso conteúdo:
1) O provedor “Microsoft.Jet.OLEDB.4.0” não está registrado na máquina local
Se por ventura você recebeu esse erro ao executar uma query em um banco de dados usando OleDb mesmo que tenha o Microsoft Office instalado corretamente é porque provavelmente a versão do driver instalado é para 32bits. Para corrigir isso, sua aplicação deve rodar em 32bits (x86). Nesse post aqui é mostrado como compilar sua aplicação desktop em x86 exclusivamente solucionando o problema. Mas para quem usa aplicações desktop terá que mudar a configuração do pool de aplicação no IIS. Para isso vá no IIS, Pools de Aplicativos e selecione o Pool usado pelas suas aplicações. Clique em Configurações Avançadas e no item Habilitar Aplicativos 32bits configure para True.
2) O inicializador de tipo de 'CrystalDecisions.CrystalReports.Engine.ReportDocument' acionou uma exceção
Caso bem semelhante ao anterior ocorre se sua máquina é 64bits e instalar o Crystal Reports 32bits (x86). O modo de compatibilidade que o Windows coloca para aplicações instaladas não funciona no caso. Para resolver isso basta instalar a versão 64bits do Crystal Reports (x64). Mas se você realizou o passo acima e está habilitado o modo de compatibilidade de 32bits no IIS então terá que usar a versão 32bits do Crystal de qualquer jeito.
Solução: Modo de compatibilidade em 32bits.
Bom se todo post fosse assim tão rápido para solucionar nossos problemas. Agora vamos alongar mais as respostas e enriquecer nosso conteúdo:
1) O provedor “Microsoft.Jet.OLEDB.4.0” não está registrado na máquina local
Se por ventura você recebeu esse erro ao executar uma query em um banco de dados usando OleDb mesmo que tenha o Microsoft Office instalado corretamente é porque provavelmente a versão do driver instalado é para 32bits. Para corrigir isso, sua aplicação deve rodar em 32bits (x86). Nesse post aqui é mostrado como compilar sua aplicação desktop em x86 exclusivamente solucionando o problema. Mas para quem usa aplicações desktop terá que mudar a configuração do pool de aplicação no IIS. Para isso vá no IIS, Pools de Aplicativos e selecione o Pool usado pelas suas aplicações. Clique em Configurações Avançadas e no item Habilitar Aplicativos 32bits configure para True.
2) O inicializador de tipo de 'CrystalDecisions.CrystalReports.Engine.ReportDocument' acionou uma exceção
Caso bem semelhante ao anterior ocorre se sua máquina é 64bits e instalar o Crystal Reports 32bits (x86). O modo de compatibilidade que o Windows coloca para aplicações instaladas não funciona no caso. Para resolver isso basta instalar a versão 64bits do Crystal Reports (x64). Mas se você realizou o passo acima e está habilitado o modo de compatibilidade de 32bits no IIS então terá que usar a versão 32bits do Crystal de qualquer jeito.
Refresh automático ou execução de script em ciclos
Postado por
Thiago Marçal
on domingo, 18 de julho de 2010
/
Marcadores:
ajax,
html,
javascript
/
Comments: (1)
Durante o desenvolvimento de muitos sistemas web nos deparamos com as seguintes situações:
Situação 1: Atualizar página automacatimente
Para essa situação, que é a mais simples, basta inserir a seguinte tag no head da página especificando a quantidade de segundos que deve aguardar para dar o refresh:
Situação 2: Executar uma função JavaScript a cada x segundos
Se derem uma olhada no post anterior do chat, verão que uso uma função chamada setTimeout() que irá registrar qual função irá executar e qual o tempo de espera. Então, coloque o seguinte código JS:
window.onload = function() {
setTimeout("FuncaoJS()", 10000);
}
function FuncaoJS(){
// Instruções
setTimeout("FuncaoJS()", 10000);
}
De forma similar, pode-se usar também a função setInterval().
Situação 3: Executar um método ASP.NET a cada x segundos sem dar refresh
Já para o ASP.NET podemos usar o AJAX. Para isso utilizaremos um Timer e um UpdatePanel. Na página, adicione o ScriptManager e insira o Timer dentro do ContentTemplate do UpdatePanel. Atribua um método no evento OnTick do Timer ficando da seguinte forma:
<Ajax:ScriptManager ID="ScriptManagerAjax" runat="server">
</Ajax:ScriptManager>
<Ajax:UpdatePanel ID="Painel" runat="server">
<ContentTemplate>
<Ajax:Timer ID="Temporizador" runat="server" Interval="10000" OnTick="ExecutaScript_Tick">
</Ajax:Timer>
</ContentTemplate>
</Ajax:UpdatePanel>
Se você deixar o Timer fora do UpdatePanel ele irá realizar a execução do bloco de script, mas irá dar PostBack e, consequentemente, refresh na página. Por isso, e mais amigável, deve-se deixar dentro.
Agora basta criar o método no Code-Behind contendo o código a ser executado:
protected void ExecutaScript_Tick(object sender, EventArgs e)
{
}
Tranquilo, né?
- Página dar refresh automaticamente a cada x segundos;
- Executar um bloco de script (JavaScript) a cada x segundos;
- Executar um bloco de código (ASP.NET) a cada x segundos sem refresh na página.
Situação 1: Atualizar página automacatimente
Para essa situação, que é a mais simples, basta inserir a seguinte tag no head da página especificando a quantidade de segundos que deve aguardar para dar o refresh:
<META HTTP-EQUIV="Refresh"
CONTENT="10;URL=http://thiagomarcal.blogspot.com">
Situação 2: Executar uma função JavaScript a cada x segundos
Se derem uma olhada no post anterior do chat, verão que uso uma função chamada setTimeout() que irá registrar qual função irá executar e qual o tempo de espera. Então, coloque o seguinte código JS:
window.onload = function() {
setTimeout("FuncaoJS()", 10000);
}
function FuncaoJS(){
// Instruções
setTimeout("FuncaoJS()", 10000);
}
De forma similar, pode-se usar também a função setInterval().
Situação 3: Executar um método ASP.NET a cada x segundos sem dar refresh
Já para o ASP.NET podemos usar o AJAX. Para isso utilizaremos um Timer e um UpdatePanel. Na página, adicione o ScriptManager e insira o Timer dentro do ContentTemplate do UpdatePanel. Atribua um método no evento OnTick do Timer ficando da seguinte forma:
<Ajax:ScriptManager ID="ScriptManagerAjax" runat="server">
</Ajax:ScriptManager>
<Ajax:UpdatePanel ID="Painel" runat="server">
<ContentTemplate>
<Ajax:Timer ID="Temporizador" runat="server" Interval="10000" OnTick="ExecutaScript_Tick">
</Ajax:Timer>
</ContentTemplate>
</Ajax:UpdatePanel>
Se você deixar o Timer fora do UpdatePanel ele irá realizar a execução do bloco de script, mas irá dar PostBack e, consequentemente, refresh na página. Por isso, e mais amigável, deve-se deixar dentro.
Agora basta criar o método no Code-Behind contendo o código a ser executado:
protected void ExecutaScript_Tick(object sender, EventArgs e)
{
}
Tranquilo, né?
Criando um Chat em ASP.NET em 1 minuto
Para quem quer ter um chat em seu web site, esse componente é uma mão na roda. Muito fácil de ser utilizado e configurado, apesar de seus bugs (irei solucioná-los no fim do post). Em poucos segundos você tem um chat funcional! A Web Furbish desenvolveu esse componente e pode ser encontrado tanto aqui quanto aqui e em vários mirros pela net. Vamos ao desenvolvimento...
Extraia os arquivos em um local onde poderá buscá-los. Agora crie um novo Web Site. Se for sua primeira vez usando o componente, primeiramente, deve-se adicionar o novo controle ao ToolBox do Visual Studio. Para isso, clique com o botão direito em algum local onde é exibido os itens e escolha a opção Choose Items:
Quando surgir a caixa de seleção de componentes, na aba .NET Framework Components, clique no botão Browse... para selecionar a DLL JaxterChat.dll na pasta onde extraiu os arquivos a princípio. Clique em OK para carregá-la. Verá que ela foi adicionada ao ToolBox. Esse passo foi o mais difícil! Em seguida copie a pasta JaxterChat (que havia junto à DLL) e incorpore-o a seu projeto. Nessa pasta contêm arquivos de imagem, som, etc. Agora é simples: arraste-o para a página para que ele seja adicionado. Pronto! Você já tem seu chat...
O resto é apenas configuração: tema, tempo de atualização, usar som, nome dos labels, etc. Veja como ficou o meu!
Tranquilo e prático, não? Antes dos bugs, vamos a alguns questionamentos?
1) Como faço para ter várias salas?
Você não precisar criar várias páginas para a cada sala. Basta que, no Page_Load, atribua o nome da sala ao controle. Exemplo: Chat.RoomName = "Blog"; O controle irá se encarregar de fazer a separação dos usuários de acordo com o nome da sala.
2) Como gravar o log das conversas?
Crie um método para o OnMessagePosted do chat. Você pode gravar em banco ou em arquivo. Ficaria mais ou menos assim:
protected void Grava_Log(object sender, WebFurbish.JaxterMessageEventArgs e)
{
string sala = e.RoomName;
string usuario = e.UserName;
string mensagemExibida = e.Message;
string mensagemHtml = e.MessageHTML;
string hora = DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss");
// Grava o log em banco ou em arquivo
}
3) Como enviar mensagens às salas (avisos de administração, etc) igual a um Broadcast?
Esse é um pouco mais complicado e demorado, então irei explicar em linhas gerais como seria:
O parâmetro false indica que essa mensagem não será processada em log (ou seja, não parassá pelo método do OnMessagePosted).
E n formas que há de customizar o chat para trabalhar da forma como desejar. Pois bem, agora vamos aos bugs encontrados. Quando levantei esses bugs enviei um e-mail para eles mas não obtive resposta até o momento (também nem tentei mais... :P).
Bug 1: A cada mensagem entrada, a barra de rolagem ao invés de acompanhar as mensagens, ela fica sempre apontada para o topo. Ou seja, ela não desce...
Notamos isso quando começa a encher de mensagens. A barra ao invés de rolar automaticamente para baixo, fica estagnada no topo. Analisando o JavaScript que ele gera, verifiquei que há um problema na função WF_goToBottomScroll. Daí, como não posso apagar ela, criei uma outra com o mesmo nome. Como há sobrecarga ela será executada também. É armengue, mas é uma solução. Como funciona essa solução? A cada 0 segundos verifico se o foco está no campo de texto digitado: se estiver, a barra da div rola automaticamente para baixo. Para que isso funcione, baixe esse script aqui para fazer uma varredura de controles HTML. E adicione o seguinte bloco de código JS na página que contêm o chat:
window.onload = function() {
setFocusTracking();
sizeMsgOut = document.getElementById('WF_msgOut').scrollHeight;
setTimeout("WF_goToBottomScroll('WF_msgOut');", 0);
}
function WF_goToBottomScroll(elemento) {
var msgOut = document.getElementById(elemento);
if (document.hasFocus) {
if (document.hasFocus.id == 'WF_textInput')
msgOut.scrollTop = msgOut.scrollHeight;
}
setTimeout("WF_goToBottomScroll('" + elemento + "');", 0);
}
Bug 2: O som não funciona!
Quando vi que iria ter som, pensei: "Bala!". Mas daí ele exige Java para rodar. Pensei novamente: "Tranquilo! Hoje na net, em sites de banco, tem que ter Java, logo pro chat vai ser pré-requisito ter também.". Instalei a versão mais recente e não funcionou! Porque, eu não sei. Como o componente é fechado, a única coisa que deu para ver é que ele chama uma classe Java SoundApplet.class já compilada. Enfim, providenciei outra solução: coloquei a propriedade EnableSound como false e adicionei algumas linhas ao script WF_goToBottomScroll para tocar um som a cada vez que é dado uma entrada de mensagem. Esse som é puro JavaScript! Primeiro, adicione uma tag de som em background em qualquer local da página, assim:
Depois crie uma variável global var sizeMsgOut = 0; antes do window.onload . Ou seja, estou criando uma variável global que irá armazenar o tamanho de minha div a cada momento e quando entrar na página pela primeira vez terá valor 0. Agora, adicione as linhas abaixo na função WF_goToBottomScroll antes do setTimeout:
if (document.getElementById('WF_msgOut').scrollHeight != sizeMsgOut) {
document.all.sound.src = "JaxterChat/Sounds/alert.au";
sizeMsgOut = document.getElementById('WF_msgOut').scrollHeight;
}
A cada iteração da função, verifico se o tamanho da div que contêm as mensagens é diferente do valor armazenado na variável. Se for é porque entrou nova mensagem logo deve tocar o som.
Esses foram dois bugs que encontrei quando estava usando-o. Pode ser que haja outros que não encontrei. Se não tiver é bom, pois é um chat bem legalzinho e fácil e manipular. Até mais!
Extraia os arquivos em um local onde poderá buscá-los. Agora crie um novo Web Site. Se for sua primeira vez usando o componente, primeiramente, deve-se adicionar o novo controle ao ToolBox do Visual Studio. Para isso, clique com o botão direito em algum local onde é exibido os itens e escolha a opção Choose Items:
Quando surgir a caixa de seleção de componentes, na aba .NET Framework Components, clique no botão Browse... para selecionar a DLL JaxterChat.dll na pasta onde extraiu os arquivos a princípio. Clique em OK para carregá-la. Verá que ela foi adicionada ao ToolBox. Esse passo foi o mais difícil! Em seguida copie a pasta JaxterChat (que havia junto à DLL) e incorpore-o a seu projeto. Nessa pasta contêm arquivos de imagem, som, etc. Agora é simples: arraste-o para a página para que ele seja adicionado. Pronto! Você já tem seu chat...
O resto é apenas configuração: tema, tempo de atualização, usar som, nome dos labels, etc. Veja como ficou o meu!
Tranquilo e prático, não? Antes dos bugs, vamos a alguns questionamentos?
1) Como faço para ter várias salas?
Você não precisar criar várias páginas para a cada sala. Basta que, no Page_Load, atribua o nome da sala ao controle. Exemplo: Chat.RoomName = "Blog"; O controle irá se encarregar de fazer a separação dos usuários de acordo com o nome da sala.
2) Como gravar o log das conversas?
Crie um método para o OnMessagePosted do chat. Você pode gravar em banco ou em arquivo. Ficaria mais ou menos assim:
protected void Grava_Log(object sender, WebFurbish.JaxterMessageEventArgs e)
{
string sala = e.RoomName;
string usuario = e.UserName;
string mensagemExibida = e.Message;
string mensagemHtml = e.MessageHTML;
string hora = DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss");
// Grava o log em banco ou em arquivo
}
3) Como enviar mensagens às salas (avisos de administração, etc) igual a um Broadcast?
Esse é um pouco mais complicado e demorado, então irei explicar em linhas gerais como seria:
- Pegaria todas as sala usando o método GetRoomList();
- E para cada sala faz-se o envio através do método SendCustomMessage().
O parâmetro false indica que essa mensagem não será processada em log (ou seja, não parassá pelo método do OnMessagePosted).
E n formas que há de customizar o chat para trabalhar da forma como desejar. Pois bem, agora vamos aos bugs encontrados. Quando levantei esses bugs enviei um e-mail para eles mas não obtive resposta até o momento (também nem tentei mais... :P).
Bug 1: A cada mensagem entrada, a barra de rolagem ao invés de acompanhar as mensagens, ela fica sempre apontada para o topo. Ou seja, ela não desce...
Notamos isso quando começa a encher de mensagens. A barra ao invés de rolar automaticamente para baixo, fica estagnada no topo. Analisando o JavaScript que ele gera, verifiquei que há um problema na função WF_goToBottomScroll. Daí, como não posso apagar ela, criei uma outra com o mesmo nome. Como há sobrecarga ela será executada também. É armengue, mas é uma solução. Como funciona essa solução? A cada 0 segundos verifico se o foco está no campo de texto digitado: se estiver, a barra da div rola automaticamente para baixo. Para que isso funcione, baixe esse script aqui para fazer uma varredura de controles HTML. E adicione o seguinte bloco de código JS na página que contêm o chat:
window.onload = function() {
setFocusTracking();
sizeMsgOut = document.getElementById('WF_msgOut').scrollHeight;
setTimeout("WF_goToBottomScroll('WF_msgOut');", 0);
}
function WF_goToBottomScroll(elemento) {
var msgOut = document.getElementById(elemento);
if (document.hasFocus) {
if (document.hasFocus.id == 'WF_textInput')
msgOut.scrollTop = msgOut.scrollHeight;
}
setTimeout("WF_goToBottomScroll('" + elemento + "');", 0);
}
Bug 2: O som não funciona!
Quando vi que iria ter som, pensei: "Bala!". Mas daí ele exige Java para rodar. Pensei novamente: "Tranquilo! Hoje na net, em sites de banco, tem que ter Java, logo pro chat vai ser pré-requisito ter também.". Instalei a versão mais recente e não funcionou! Porque, eu não sei. Como o componente é fechado, a única coisa que deu para ver é que ele chama uma classe Java SoundApplet.class já compilada. Enfim, providenciei outra solução: coloquei a propriedade EnableSound como false e adicionei algumas linhas ao script WF_goToBottomScroll para tocar um som a cada vez que é dado uma entrada de mensagem. Esse som é puro JavaScript! Primeiro, adicione uma tag de som em background em qualquer local da página, assim:
<BGSOUND id="sound" src="">
Depois crie uma variável global var sizeMsgOut = 0; antes do window.onload . Ou seja, estou criando uma variável global que irá armazenar o tamanho de minha div a cada momento e quando entrar na página pela primeira vez terá valor 0. Agora, adicione as linhas abaixo na função WF_goToBottomScroll antes do setTimeout:
if (document.getElementById('WF_msgOut').scrollHeight != sizeMsgOut) {
document.all.sound.src = "JaxterChat/Sounds/alert.au";
sizeMsgOut = document.getElementById('WF_msgOut').scrollHeight;
}
A cada iteração da função, verifico se o tamanho da div que contêm as mensagens é diferente do valor armazenado na variável. Se for é porque entrou nova mensagem logo deve tocar o som.
Esses foram dois bugs que encontrei quando estava usando-o. Pode ser que haja outros que não encontrei. Se não tiver é bom, pois é um chat bem legalzinho e fácil e manipular. Até mais!
Gerando o Código de Verificação (CODVER) para o Komerci em ASP.NET ou em Qualquer Linguagem
Quem está começando a fazer a integração de sua loja virtual com o Komerci e está lendo o manual da versão Integrada, se deparou com a parte da geração do código de verificação. Eles disponibilizam uma classe Java denominada CodVer.class. Daí você pensa: "Para eles disponibilizarem uma classe específica em Java deve ser porque é algo muito específico ou cabuloso!". Mas não é... Não sei porque no próprio manual eles não colocam um pseudo-algoritmo ou diagramas que possam facilitar para a elaboração nas demais linguagens. No mesmo manual eles dizem que disponibilizam um ActiveX para quem usa ASP Clássico. É de dar risada! Bem, o código é bem simples. Já converti do Java para C# e, para quem está familiarizado com C/Java, vai entender o algoritmo rapidinho e elaborar o seu também:
public string GeraCodigoVerificao(string _numfil, string _valor)
{
// Início da codificação
string codigo = string.Empty;
// Número da filiação
int numfil = 0;
numfil = int.Parse(_numfil);
// Total
int total = 0;
string parteInteira = _valor.Substring(0, _valor.IndexOf('.'));
total = int.Parse(parteInteira);
// Codificação a hora
int segundosAgora = DateTime.Now.Second;
int segundosAgoraCodificados = 0;
switch (segundosAgora)
{
case 0:
segundosAgoraCodificados = 11;
break;
case 1:
segundosAgoraCodificados = 17;
break;
case 2:
segundosAgoraCodificados = 21;
break;
case 3:
segundosAgoraCodificados = 31;
break;
case 4:
segundosAgoraCodificados = 56;
break;
case 5:
segundosAgoraCodificados = 34;
break;
case 6:
segundosAgoraCodificados = 42;
break;
case 7:
segundosAgoraCodificados = 3;
break;
case 8:
segundosAgoraCodificados = 18;
break;
case 9:
segundosAgoraCodificados = 13;
break;
case 10:
segundosAgoraCodificados = 12;
break;
case 11:
segundosAgoraCodificados = 18;
break;
case 12:
segundosAgoraCodificados = 22;
break;
case 13:
segundosAgoraCodificados = 32;
break;
case 14:
segundosAgoraCodificados = 57;
break;
case 15:
segundosAgoraCodificados = 35;
break;
case 16:
segundosAgoraCodificados = 43;
break;
case 17:
segundosAgoraCodificados = 4;
break;
case 18:
segundosAgoraCodificados = 19;
break;
case 19:
segundosAgoraCodificados = 14;
break;
case 20:
segundosAgoraCodificados = 9;
break;
case 21:
segundosAgoraCodificados = 20;
break;
case 22:
segundosAgoraCodificados = 23;
break;
case 23:
segundosAgoraCodificados = 33;
break;
case 24:
segundosAgoraCodificados = 58;
break;
case 25:
segundosAgoraCodificados = 36;
break;
case 26:
segundosAgoraCodificados = 44;
break;
case 27:
segundosAgoraCodificados = 5;
break;
case 28:
segundosAgoraCodificados = 24;
break;
case 29:
segundosAgoraCodificados = 15;
break;
case 30:
segundosAgoraCodificados = 62;
break;
case 31:
segundosAgoraCodificados = 25;
break;
case 32:
segundosAgoraCodificados = 34;
break;
case 33:
segundosAgoraCodificados = 59;
break;
case 34:
segundosAgoraCodificados = 37;
break;
case 35:
segundosAgoraCodificados = 45;
break;
case 36:
segundosAgoraCodificados = 6;
break;
case 37:
segundosAgoraCodificados = 25;
break;
case 38:
segundosAgoraCodificados = 16;
break;
case 39:
segundosAgoraCodificados = 27;
break;
case 40:
segundosAgoraCodificados = 63;
break;
case 41:
segundosAgoraCodificados = 26;
break;
case 42:
segundosAgoraCodificados = 35;
break;
case 43:
segundosAgoraCodificados = 60;
break;
case 44:
segundosAgoraCodificados = 38;
break;
case 45:
segundosAgoraCodificados = 46;
break;
case 46:
segundosAgoraCodificados = 7;
break;
case 47:
segundosAgoraCodificados = 26;
break;
case 48:
segundosAgoraCodificados = 17;
break;
case 49:
segundosAgoraCodificados = 28;
break;
case 50:
segundosAgoraCodificados = 14;
break;
case 51:
segundosAgoraCodificados = 36;
break;
case 52:
segundosAgoraCodificados = 2;
break;
case 53:
segundosAgoraCodificados = 39;
break;
case 54:
segundosAgoraCodificados = 47;
break;
case 55:
segundosAgoraCodificados = 8;
break;
case 56:
segundosAgoraCodificados = 29;
break;
case 57:
segundosAgoraCodificados = 22;
break;
case 58:
segundosAgoraCodificados = 55;
break;
case 59:
segundosAgoraCodificados = 33;
break;
}
// Cálculos e atribuições
segundosAgora = segundosAgoraCodificados;
string pad = string.Empty;
if (segundosAgora < 10)
pad = "0";
else
pad = "";
string ipremoto = Request.ServerVariables["REMOTE_ADDR"];
int tamIP = ipremoto.Length;
int i_5_ = total + segundosAgora;
int i_6_ = segundosAgora + tamIP;
int i_7_ = segundosAgora * numfil;
int i_8_ = i_7_.ToString().Length;
// Monta o código
codigo = i_7_.ToString() + i_5_.ToString() + i_6_.ToString() + "-" + i_8_.ToString() + pad + segundosAgora.ToString();
// Retorna
return codigo;
}
public string GeraCodigoVerificao(string _numfil, string _valor)
{
// Início da codificação
string codigo = string.Empty;
// Número da filiação
int numfil = 0;
numfil = int.Parse(_numfil);
// Total
int total = 0;
string parteInteira = _valor.Substring(0, _valor.IndexOf('.'));
total = int.Parse(parteInteira);
// Codificação a hora
int segundosAgora = DateTime.Now.Second;
int segundosAgoraCodificados = 0;
switch (segundosAgora)
{
case 0:
segundosAgoraCodificados = 11;
break;
case 1:
segundosAgoraCodificados = 17;
break;
case 2:
segundosAgoraCodificados = 21;
break;
case 3:
segundosAgoraCodificados = 31;
break;
case 4:
segundosAgoraCodificados = 56;
break;
case 5:
segundosAgoraCodificados = 34;
break;
case 6:
segundosAgoraCodificados = 42;
break;
case 7:
segundosAgoraCodificados = 3;
break;
case 8:
segundosAgoraCodificados = 18;
break;
case 9:
segundosAgoraCodificados = 13;
break;
case 10:
segundosAgoraCodificados = 12;
break;
case 11:
segundosAgoraCodificados = 18;
break;
case 12:
segundosAgoraCodificados = 22;
break;
case 13:
segundosAgoraCodificados = 32;
break;
case 14:
segundosAgoraCodificados = 57;
break;
case 15:
segundosAgoraCodificados = 35;
break;
case 16:
segundosAgoraCodificados = 43;
break;
case 17:
segundosAgoraCodificados = 4;
break;
case 18:
segundosAgoraCodificados = 19;
break;
case 19:
segundosAgoraCodificados = 14;
break;
case 20:
segundosAgoraCodificados = 9;
break;
case 21:
segundosAgoraCodificados = 20;
break;
case 22:
segundosAgoraCodificados = 23;
break;
case 23:
segundosAgoraCodificados = 33;
break;
case 24:
segundosAgoraCodificados = 58;
break;
case 25:
segundosAgoraCodificados = 36;
break;
case 26:
segundosAgoraCodificados = 44;
break;
case 27:
segundosAgoraCodificados = 5;
break;
case 28:
segundosAgoraCodificados = 24;
break;
case 29:
segundosAgoraCodificados = 15;
break;
case 30:
segundosAgoraCodificados = 62;
break;
case 31:
segundosAgoraCodificados = 25;
break;
case 32:
segundosAgoraCodificados = 34;
break;
case 33:
segundosAgoraCodificados = 59;
break;
case 34:
segundosAgoraCodificados = 37;
break;
case 35:
segundosAgoraCodificados = 45;
break;
case 36:
segundosAgoraCodificados = 6;
break;
case 37:
segundosAgoraCodificados = 25;
break;
case 38:
segundosAgoraCodificados = 16;
break;
case 39:
segundosAgoraCodificados = 27;
break;
case 40:
segundosAgoraCodificados = 63;
break;
case 41:
segundosAgoraCodificados = 26;
break;
case 42:
segundosAgoraCodificados = 35;
break;
case 43:
segundosAgoraCodificados = 60;
break;
case 44:
segundosAgoraCodificados = 38;
break;
case 45:
segundosAgoraCodificados = 46;
break;
case 46:
segundosAgoraCodificados = 7;
break;
case 47:
segundosAgoraCodificados = 26;
break;
case 48:
segundosAgoraCodificados = 17;
break;
case 49:
segundosAgoraCodificados = 28;
break;
case 50:
segundosAgoraCodificados = 14;
break;
case 51:
segundosAgoraCodificados = 36;
break;
case 52:
segundosAgoraCodificados = 2;
break;
case 53:
segundosAgoraCodificados = 39;
break;
case 54:
segundosAgoraCodificados = 47;
break;
case 55:
segundosAgoraCodificados = 8;
break;
case 56:
segundosAgoraCodificados = 29;
break;
case 57:
segundosAgoraCodificados = 22;
break;
case 58:
segundosAgoraCodificados = 55;
break;
case 59:
segundosAgoraCodificados = 33;
break;
}
// Cálculos e atribuições
segundosAgora = segundosAgoraCodificados;
string pad = string.Empty;
if (segundosAgora < 10)
pad = "0";
else
pad = "";
string ipremoto = Request.ServerVariables["REMOTE_ADDR"];
int tamIP = ipremoto.Length;
int i_5_ = total + segundosAgora;
int i_6_ = segundosAgora + tamIP;
int i_7_ = segundosAgora * numfil;
int i_8_ = i_7_.ToString().Length;
// Monta o código
codigo = i_7_.ToString() + i_5_.ToString() + i_6_.ToString() + "-" + i_8_.ToString() + pad + segundosAgora.ToString();
// Retorna
return codigo;
}
Dar POST em um Form e Redirecionar para Página Externa com ASP.NET
Recentemente estava programando o envio de informações de pagamento para o Komerci (estrutura de pagamentos da Redecard) e em certo momento precisaria realizar um POST a um endereço passando parâmetros/variáveis a ela. Antes de partir para a solução, vou revisar aqui alguns conceitos básicos que podem ser usados para esse tipo de envio:
Agora vamos criar um método que irá criar os inputs com atributo hidden e seus respectivos valores, montar um JavaScript que força o POST e "startar" o processo:
private void PostRedirectAspNet()
{
StringBuilder formulario = new StringBuilder();
// Adiciono todos os campos e seus valores que devem ser passados via POST
formulario.Append("<input type=\"hidden\" name=\"TRANSACAO\" value=\"04\">");
// Crio um JavaScript para forçar o POST na página corrente
formulario.Append("<script language=\"javascript\">");
formulario.Append("var theForm = document.forms['formAsp']; if (!theForm) { theForm = document.formAsp; } ");
formulario.Append("theForm.action = \"http://thiagomarcal.blogspot.com\";");
formulario.Append("theForm.method = \"post\";");
formulario.Append("theForm.submit();");
formulario.Append("</script>");
// Aplica o script gerado no Literal para iniciar o processo
FormularioPost.Text = formulario.ToString();
}
Assim, basta chamá-lo onde quiser que ele irá gerar as tags HTML contendo as informações desejadas, realizará o POST e, consequentemente, seu redirecionamento. Bem simples, não? Esse método (de fazer) pode ser aproveitado para quaisquer linguagem de programação (PHP, Java, ASP, .NET, CodFusion, etc). O importante é como providenciar seu funcionamento de acordo com a lógica.
- Responde.Redirect: Por esse método só podemos passar os parêmetros via GET;
- Server.Transfer: Por esse método podemos usar o POST mas se o destino estiver no mesmo domínio da aplicação;
- HttpWebRequest: Por esse método você pode fazer uma requisição através de uma conversão dos dados em bytes passando via POST/GET, contudo não há como fazer um redirecionamento;
- WebClient: Por esse método pode-se realizar a passagem de parâmetros, mas também não consegue fazer o redirecionamento após o envio.
Agora vamos criar um método que irá criar os inputs com atributo hidden e seus respectivos valores, montar um JavaScript que força o POST e "startar" o processo:
private void PostRedirectAspNet()
{
StringBuilder formulario = new StringBuilder();
// Adiciono todos os campos e seus valores que devem ser passados via POST
formulario.Append("<input type=\"hidden\" name=\"TRANSACAO\" value=\"04\">");
// Crio um JavaScript para forçar o POST na página corrente
formulario.Append("<script language=\"javascript\">");
formulario.Append("var theForm = document.forms['formAsp']; if (!theForm) { theForm = document.formAsp; } ");
formulario.Append("theForm.action = \"http://thiagomarcal.blogspot.com\";");
formulario.Append("theForm.method = \"post\";");
formulario.Append("theForm.submit();");
formulario.Append("</script>");
// Aplica o script gerado no Literal para iniciar o processo
FormularioPost.Text = formulario.ToString();
}
Assim, basta chamá-lo onde quiser que ele irá gerar as tags HTML contendo as informações desejadas, realizará o POST e, consequentemente, seu redirecionamento. Bem simples, não? Esse método (de fazer) pode ser aproveitado para quaisquer linguagem de programação (PHP, Java, ASP, .NET, CodFusion, etc). O importante é como providenciar seu funcionamento de acordo com a lógica.
NfseUtil - Utilitário e Código-fonte de Aplicativo que Assina e Envia os XMLs para emissão da Nota Fiscal Eletrônica
Postado por
Thiago Marçal
on quinta-feira, 1 de julho de 2010
/
Marcadores:
nfe,
nota fiscal eletrônica,
salvador,
xml
/
Comments: (18)
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:
Usando Certificado Digital para Nota Fiscal Eletrônica no Windows Server 2003/2008
Postado por
Thiago Marçal
/
Marcadores:
certificado digital,
linux,
nfe,
nota fiscal eletrônica,
salvador,
windows,
xml
/
Comments: (2)
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:
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.






