while ( TheEarth.IsRunning() &&
ThereIsHope &&
DateTime.Today.Day.Equals(25) &&
DateTime.Today.Month.Equals(12))
{
Console.WriteLine("Feliz Natal");
}
23 de dez. de 2008
Feliz Natal
Posted by Edson Dias at 11:44 0 comments
Labels: Natal
6 de dez. de 2008
Feriados móveis
Estava abrindo minhas correspondências essa semana e achei um envelope do meu contador, que recebo todo ano em Dezembro, um calendário do ano seguinte (e um boleto bancário do 13º, óbvio).
Daí comecei a ver os feriados do ano que vem, e que são muitos.
Lembrei de uma coisa interessante, que nem todo mundo sabe: como calcular feriados móveis.
Apenas por curiosidade, os calendários são baseados em eventos astrológicos, e obviamente a mudança dos feriados móveis também é baseada em cálculos astrológicos.
Muita gente se pergunta porque o Carnaval sempre cai num dia diferente todo ano, as vezes até em outro mês.
A base de todos feriados móveis é a data da Páscoa.
Carnaval = Páscoa – 47 dias
Sexta Feira Santa = Páscoa – 2 dias
CorpusChristi = Páscoa + 60 dias
A data também é móvel e é calculada através de uma fórmula muito doida.
Encontrei uns documentos antigos na minha pesquisa e fiz uma rotina em Visual Basic há muito tempo (no mínimo uns 10 anos).
Hoje resolvei convertê-la pra C# para utilizar em um sistema que estou trabalhando.
Vamos ao código:
static void Main(string[] args)O código do cálculo da Páscoa
{
DateTime dtPascoa = DataPascoa(2009);
DateTime dtCarnaval = dtPascoa.AddDays(-47);
DateTime dtSextaSanta = dtPascoa.AddDays(-2);
DateTime dtCorpusChristi = dtPascoa.AddDays(60);
Console.WriteLine(string.Format("Páscoa: {0}", dtPascoa.ToLongDateString()));
Console.WriteLine(string.Format("Carnaval: {0}", dtCarnaval.ToLongDateString()));
Console.WriteLine(string.Format("Sexta-Feira Santa: {0}", dtSextaSanta.ToLongDateString()));
Console.WriteLine(string.Format("Corpus Christi: {0}", dtCorpusChristi.ToLongDateString()));
Console.ReadKey();
}
static DateTime DataPascoa(int nYear)
{
int nGold = 0;
int nCent = 0;
int nCorx = 0;
int nCorz = 0;
int nSunday = 0;
int nEpact = 0;
int nMoon = 0;
int nMonth = 0;
int nDay = 0;
// nGold, é o Golden number
nGold = (nYear % 19) + 1;
// nCent é o Século
nCent = (nYear / 100) + 1;
// nCorx é o número de anos em que o bissexto foi retirado para sincronizar
nCorx = ((3 * nCent) / 4 - 12);
// nCorz é uma correção para sincronizar a Páscoa com a órbita da Lua
nCorz = ((8 * nCent + 5) / 25 - 5);
nSunday = ((5 * nYear) / 4 - nCorx - 10);
// nEpact é a ocorrencia de uma Lua cheia
nEpact = ((11 * nGold + 20 + nCorz - nCorx) % 30);
if (nEpact < 0)
nEpact = nEpact + 30;
if (((nEpact == 25) && (nGold > 11)) || (nEpact == 24))
nEpact = nEpact + 1;
// Lua cheia - a n ésima lua de Março é o calendário da lua cheia
nMoon = 44 - nEpact;
if (nMoon < 21)
nMoon = nMoon + 30;
// Avança ao domingo
nMoon = (nMoon + 7 - ((nSunday + nMoon) % 7));
// obtém o mês e o dia
if (nMoon > 31)
{
nMonth = 4;
nDay = nMoon - 31;
}
else
{
nMonth = 3;
nDay = nMoon;
}
return new DateTime(nYear, nMonth, nDay);
}
Posted by Edson Dias at 23:08 1 comments
5 de dez. de 2008
Download de arquivos dinâmicos
Download de arquivos gerados dinamicamente é uma rotina comum em muitos sites.
Já precisei fazer isso diversas vezes e o código normalmente se parece com isso:
Response.AddHeader("Content-Size", bytArq.Length.ToString());onde:
Response.AddHeader("Content-Disposition", "attachment; filename=" +
NomeArquivo);
Response.OutputStream.Write(bytArq, 0, bytArq.Length);Response.End();
byteArq é um byte [] do conteudo do arquivo, sendo ele texto ou binárioAté aí nenhuma novidade, mas vamos aos desafios.
NomeArquivo é a o nome padrão sugerido pelo browser ao gravar o arquivo.
Qual o problema do código acima ?
Se eu quisesse fazer o download do arquivo e logo em seguida atualizar algum campo na página, como por exemplo um label "Arquivo enviado com sucesso" ?
Com o código acima, não seria possível.
A linha Response.End(), interrompe a execução da página, e faz com que qualquer código logo após seja ignorado (pelo menos código que gere html de retorno).
Por quê essa linha é necessária ?
Porque sem ela o código no .cs seria executado e logo após o browser iria redenderizar a execução do aspx, o que faria com que o resultado gerado seria a combinação do arquivo mais o html, corrompendo o arquivo.
Na prática não é possível enviar 2 conteúdos ao browser simultaneamente, ou seja, ou eu envio o html, ou envio o arquivo.
Vamos aos workarounds:
E se ao invés de escrever os bytes do arquivo, eu abrisse uma janela, onde lá sim, escreveria o byte array, e na minha página principal continuaria meu código?
pagina.aspx, onde faria a chamada do download do arquivo
download.aspx, um arquivo sem html no aspx
No código na pagina.aspx:
Um método para escrever abrir a página de download
void DownloadArquivo(Page p, byte[] bytArq, string NomeArquivo)
{
Session["downloadBytes"] = bytArq;
Session["downloadName"] = NomeArquivo;
System.Text.StringBuilder s = new System.Text.StringBuilder();
s.Append("\n<SCRIPT LANGUAGE='JavaScript'>\n");
s.Append("function download()");
s.Append("{\n");
s.Append(" window.open('download.aspx', 'Download', 'toolbar=no,
location=no, directories=no, status=yes, menubar=no, scrollbars=no,
resizable=no, titlebar=no, copyhistory=no, width=100, height=100, left=0,
top=0');\n");
s.Append("}\n");
s.Append("window.onload = download;\n");
s.Append("</SCRIPT>");
p.RegisterClientScriptBlock("download", s.ToString());
}
A chamada desse método é bem simples, em qualquer botão de processamento e download seria:
// chame seu metodo que gere o arquivo ou pegue-o do banco de dados
byte [] arq = GeraSeuArquivo();
DownloadArquivo(this, arq, "meuarquivo.ext");
lblMeuLabel.Text = "Pronto o arquivo foi enviado para o browser";
No código no download.aspx, apenas o minimo necessário
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="download.aspx.cs" Inherits="download" Title="Download..." %>
O código no codebehind dessa página teria apenas o método Page_Load()protected void Page_Load(object sender, EventArgs e)
{
byte[] bytArq;
string NomeArquivo;
if (Session["downloadBytes"] != null)
{
bytArq = (byte[])Session["downloadBytes"];
if (bytArq.Length > 0)
{
NomeArquivo = (string)Session["downloadName"];
Session["downloadBytes"] = null;
Session["downloadName"] = null;
Response.AddHeader("Content-Disposition", "attachment; filename=" +
NomeArquivo);
Response.AddHeader("Content-Type", "application/force-download");
Response.AddHeader("Content-Type", "application/octet-stream");
Response.AddHeader("Content-Type", "application/download");
Response.AddHeader("Content-Description", "File Transfer");
Response.OutputStream.Write(bytArq, 0, bytArq.Length);
}
Response.End();
}
}
Como funciona a mágica:
A página irá gerar o arquivo (byte array) e renderizará um código javascript que abrirá um popup.
Antes de terminar a execução da pagina.aspx ela irá armazenar o conteudo desse arquivo na Session.
Ao termino da execução, o popup irá começar e executará o Page_Load
Nesse método, o download.aspx irá recuperar esse arquivo, removê-lo da Session e renderizá-lo no browser.
Simples e direto.
Limitações:
A solução funciona, mas tem suas limitações: como a transferência de conteúdo é feita através da Session, durante essa transferência, o servidor irá ocupar esse espaço de memória (mesmo que removendo logo em seguida), o que na prática quer dizer que se for transferido um arquivo muito grande, poderá ocorrer um OutOfMemory Exception.
Taí, duvido vocês testarem.
Posted by Edson Dias at 18:46 0 comments
Labels: download, response.end
O porquê de um blog
Estava aqui pensando comigo, o porquê de se criar um blog e, conversando com meu colega Vinicius Canto, achei um motivo, e dos bons.
Backup das minhas idéias !
Show de bola.
Sempre fico doido quando quero fazer uma simples rotina que já fiz em outro projeto ou outra empresa e nunca lembro onde guardei aquele pedaço de código.
Agora sim, meus problemas acabaram !
Simplesmente vou guardar tudo online.
Estava querendo escrever há um bom tempo, mas nunca há tempo.
Já recebi convites para escrever para revistas, mas o problema, como sempre é o tempo.
A vantagem do blog nessa hora é justamente essa. Numa revista existe a "obrigatoriedade" de ter um artigo regular numa coluna, e num blog não, vou escrevendo quando der.
Sem contar que o alcance é maior.
Taí, gostei da idéia.
Posted by Edson Dias at 10:36 6 comments