Byte[] para String e vice-versa

Algo que geralmente me faz confusão é a conversão de tipos. Especialmente coisas que são supostamente simples, como a conversão de um array de bytes para string, ou uma string para um array de bytes. Éra de, à primeira vista, e tendo em conta a forma como é armazenado um caracter de uma string – é geralmente um byte, em que o valor do byte é o código do caracter – considerar que a convesão poderia ser feita directamente, através de um cast. Algo como:

string a = (string)b; //em que b é um byte[]

Pois, mas não dá. E a explicação até é simples – a codificação dos caracteres pode ser do mais diverso (ASCII, UTF7, UTF8, UTF16, UTF32…), e é importante que o programa conheça qual. Assim sendo, é de aproveitar os encoders que o .NET oferece no namespace System.Text.

Para converter de string para byte[]:

System.Text.ASCIIEncoding  encoding = new System.Text.ASCIIEncoding();
byte[] bArray = encoding.GetBytes(str);

e de byte[] para string:

System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
string str = enc.GetString(bArray);

Neste caso é usado a mapeamento de valores para caracteres ASCII.

Microsoft adopta jQuery para a plataforma.

É oficial o anúncio. A Microsoft irá adoptar o framework aberto de javascript na sua plataforma, inalterado. jQuery fará parte da plataforma sendo distribuído com o Visual Studio e e terá suporte intelissense também, o que é muito útil quando se trabalha com esta biblioteca (ou com qualquer outra linguagem de programação).

Os anúncios em:
jQuery, Microsoft, and Nokia
jQuery to ship with ASP.NET MVC and Visual Studio
jQuery and Microsoft

Limitações do IIS 7 no Windows Vista

É pelo menos a segunda vez que tenho que enfrentar problemas de limitações do sistema operativo, e é nesta altura que mais detesto a Microsoft e o seu sistema operativo. Mas enfim, são as regras do jogo que nos impõe. E é nesta altura que gostava que o mundo fosse o Ubuntu.. hehehe

Desta vez, no desenvolvimento de uma aplicação que faz grande uso de serviços, e até encadeamento de acessos. Em termos de produção, trata-se de um sistema distribuído, mas todo o desenvolvimento é efectuado numa só máquina, com os diversos serviços integrados em directorias virtuais com se fossem servidores distintos. Uma abstracção que permite-me ter alguma flexibilidade no desenvolvimento da(s) aplicação(ões).

Esta abordagem tem, no entanto, problemas associadas. Cada chamada a um serviço é uma chamada na contagem, e porque o processo exige pedidos síncronos, o anterior tem que aguardar pela resposta do seguinte. Após horas a batalhar com a questão e após um esforço grande de logging, encontrei o local do problema – uma operação que teoricamente é simples e rápida, mas que exigia um pedido a um serviço. O tempo de execução entre a chamada anterior e a seguinte era sempre de 1m30s. Só depois deste periodo (em que a aplicação dava um timeout, nas camadas superiores) é que os pedidos em espera eram executados (quase instantaneamente).

O giro disto tudo, e o que me levou a desconfiar do IIS / Vista foi o facto de este problema surgir apenas com o acesso à aplicação via IIS. Usando o servidor de desenvolvimento do Visual Studio, o pedido passava sempre, sem problemas. Detectado o ponto de falha, e com este conhecimento da potencial falha, um pouco de pesquisa no Google apresenta a causa. IIS 7 em Vista Home Premium.

O Home Premium admite sevrir páginas e desenvolvimento para aplicações simples, sem dúvida. E até agora só encontrei dois problemas com ele em termos de desenvolvimento. Mas para algumas aplicações mais complexa como o caso da minha torna-se problemático e é muito díficil encontrar o bicho que causa o problema.

Em Stuff that Just Works, de Cal Zant há uma página que apresenta o conjunto de limitações que as versões do Windows apresentam. Com o XP Pro, e IIS 6, a limitação era de 1 site e 10 ligações concorrentes. O XP, versões básicas, não permitiam o IIS. Com o vista, mais ou menos a mesma situação surge – para as versões Business e superiores, o numero de ligações concorrentes são ilimitadas, mas passou a haver limite no numero de pedidos simultâneos, e a restrição do número de sites desapareceu.

Já com o Home Basic Premium, que é o unico dos Home a suportar o IIS, a intenção é suportar as necessidades de desenvolvimento casual e portanto entram as limitações – processamento de três pedidos em simultâneo e sem o suporte a configurações de segurança avançadas – exactamente os dois pontos problemáticos para mim…

Em termos de mudança relativo ao IIS 6 no XP Pro, enquanto neste era possível que apenas 10 utilizares dessem inicio a sessão (mas podendo fazer quantos pedidos quisesse), com o IIS 7 em Vista, podem estar ligados quantos quiserem, mas apenas 10 (ou 3) pedidos estarão a ser processados em qualquer momento e as restantes permanecem em fila de espera o que permite que os utilizadores se mantenham ligados à aplicação, mas eventualmente com demora na resposta. No meu caso, como os 3 em execução estavam dependentes de um 4 que estava em espera, apenas o timeout do primeiro permitiu a continuação da execução.

Acredito que sejam limitações impostas pela Microsoft para de alguma forma puxar as empresas a comprarem as versões de servidor (em termos de ambiente de utilização) e para o programador mover-se para um SO “mais completo”. Mas que são situações chatas (e caras), lá isso são!!!

Em IIS.Net, há ainda a lista completa das diferenças do IIS entre versões do Vista…

Frases…

“The key to being an effective programmer is maximizing the portion of
the program that you can safely ignore while working on any one section
of code.”

Steve McConnell

DSL-Tools – Ferramentas para contruir Ferramentas

Os DSL (Domain Specific Languages) existem há muito para nos facilitar a vida. São linguagens que nos permitem manipular processo em domínios específicos. SQL e HTML são bons exemplos de DSLs – SQL permite desenvolver métodos de manipulação de dados no domínio das bases de dados (e não serve para mais) como também o HTML permite formatar dados para visualização num browser mas pouco mais. Contrariamente, C#, C++ entre outros são linguagens mais generalizadas, que permitem trabalhar em muitos domínios.

Nos últimos dias tenho estado a pesquisar alguns conceitos e componentes e de alguma forma tropecei nos DSL Tools para o Visual Studio. Até recentemente, as DSLs eram puramente textuais, mas agora começa a ser mais frequentemente ter DSLs gráficos. A vantagem é que, além de permitirem expressar melhor conceitos de um domínio específico, as suas representações poderem ser expressas por código de uma forma automatizada (com geradores de código). Um bom exemplo deste processo creio ser os diagramas de classes que o VS suporta actualmente onde a manipulação do gráfico gera código especifico ao domínio das classes, ou os diagramas de bases de dados do SQL Server, que tem o mesmo comportamento.

Agora, o VS suporta a criação de DSLs através da DSL-Tools – são projectos incluídos no SDK de extensão do VS, e que permitem criar aplicações semelhantes ao VS, mas específicos ao domínio da aplicação que se pretende construir. Um diagrama de classes como no UML nem sempre é capaz de demonstrar os conceitos que uma DSL consegue. E a capacidade de gerar código é uma mais valia, sem dúvida. E logo pensei no gerador de código… porque não tentar implementa-lo no DSL, onde o domínio é, para efeitos concretos, a framework que pretendo implementar?

Como é natural, começar com conceitos novos não é nada simples, mas achei um artigo/tutorial muito interessante no Linha de Código. O artigo “DSL Tools – Melhore sua produtividade através de linguagens visuais de domínio-específico no Visual Studio.NET” (vou a meio) apresenta muito bem os conceitos das DSLs esclarecendo muitas questões que me surgiram nos primeiros artigos que encontrei. Muito completo, muito explicado, e com um exemplo simples, mas completo. Mas não é unico, naturalmente. Um outro artigo de interesse é o Domain-Specific Development in Visual Studio no Code-Magazine. E há sempre o Learn Visual Studio Extensability do MSDN.

Parece-me uma área muito interessante e com verdadeiro potencial em termos de produtividade…

CommandTimeout para problemas de timeout na BD

Um pequeno problema que resolvi hoje, que deve ser comum com alguns procedimentos pesados em bases de dados, é da própria base de dados lançar um timeout num procedimento. Para todos os efeitos, as bases de dados como SQL Server geralmente definem um período finito de tempo máximo para a ligação, de modo a evitar potenciais deadlocks ao sistema. O “erro” por timeout eleva uma excepção que no SQL Server 2005 é do tipo SQLException:

System.Data.SqlClient.SqlException: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. at System.Data.SqlClient.SqlInternalConnection

Entre a base de dados e o .NET, há algumas formas em como podemos alterar o período máximo de execução. O primeiro é na própria base de dados, onde podemos alterar o valor pro defeito. No caso do SQL Server (Express 2005) o valor é de 600s. Se colocarmos o valor 0, o timeout é anulado e a base só termina quando finalizar o procedimento que tem em curso, o que pode ser perigoso.

Em termos de .NET e no caso de estar a utilizar a classe SQLCommand para enviar os comandos à base de dados, uma hipotese é na connection string usada para ligar à base de dados inserir um Connect Timeout do tipo:

 

Isto naturalmente impõe o tempo de timeout para todas as ligações efectuadas com a string, o que poderá ter ou não interesse. Se a alteração interessar apenas a um comando ou um conjunto restrito de comandos, será de todo o interesse estabelecer o timeout para apenas o comando em questão. Inicializando um SqlCommand sobre uma conecção, é possível definir o timeout:

SQLConnection con = new SQLConnection(connectionString);
//definir a query se necessário
SQLCommand cmd = new SQLCommand(query, con);
cmd.CommandTimeout = 500;
//(...)

É também importante notar que o Command Timeout é diferente de um Connection Timeout. Connection Timeout está ligado ao processo de tentativa de ligação, enquanto o Command Timeout está ligado ao procedimento em si, e o tempo que demora a completar. Definir o CommandTimeout resultou para o meu problema onde adicionei a linha de código com um tempo suficientemente alto (e definido no ficheiro de configuração).

Mais info pode ser encontrado em:
Forums.ASP.Net
CommandTimeout no MSDN
ConnectionTimeout no MSDN

Strings de formatação de DateTime em C# (VB)

É uma tarefa comum formatar instâncias de data e hora nas aplicações para correcto armazenamento ou apresentação. Felizmente, o objecto DateTime tem na sua definição métodos que permitem formatar o valor nos mais diversos formatos, o que simplifica o processo de apresentação de valores, mas não só. Por exemplo, numa base de dados SQLite (e não só), é conveniente enviar o valor da data e hora no formato correcto, para evitar erros nas operações.

O DateTime, como a generalidade das classes do framework, tem um método de ToString(), com diversos overloads, onde um deles é:

string DateTime.ToString(string format); 

Este método admite uma string de formatação do valor que retorna, no formato de string. Se bem que a construção da string não é de todo difícil, é importante escolher a correcta e ter o cuidado de não confundir alguns casos de maiúsculas e minúsculas. Produzi um pequeno exemplo no Snippet Compiler para demonstrar o conceito, e as diferenças entre cada caracter ou combinação:

	public static void RunSnippet()
	{

		DateTime agora = DateTime.Now; //02-09-2008 19:43:25
		
		//ToString por defeito
		WL("null :" + agora.ToString()); //02-09-2008 19:43:25		
		
		//date / time completos
		WL("d : " + agora.ToString("d")); //02-09-2008
		WL("D : " + agora.ToString("D")); //terça-feira, 2 de Setembro de 2008
		WL("t : " + agora.ToString("t")); //19:43
		WL("T : " + agora.ToString("T")); //19:43:25
		WL("s : " + agora.ToString("s")); //2008-09-02T19:43:25
		WL("f : " + agora.ToString("f")); //terça-feira, 2 de Setembro de 2008 19:43
		WL("F : " + agora.ToString("F")); //terça-feira, 2 de Setembro de 2008 19:43:25
		WL("g : " + agora.ToString("g")); //02-09-2008 19:43
		WL("G : " + agora.ToString("G")); //02-09-2008 19:43:25
		WL("r : " + agora.ToString("r")); //Tue, 02 Sep 2008 19:53:20 GMT
		WL("u : " + agora.ToString("u")); //2008-09-02 19:53:20Z
		WL("U : " + agora.ToString("U")); //terça-feira, 2 de Setembro de 2008 18:53:20
		
		//formato de dia
		WL("dd : " + agora.ToString("dd")); //02
		WL("ddd : " + agora.ToString("ddd")); //ter
		WL("dddd : " + agora.ToString("dddd")); //terça-feira

		//formato do mês
		WL("m : " + agora.ToString("m")); //2-9
		WL("M : " + agora.ToString("M")); //2-9
		WL("MM : " + agora.ToString("MM")); //09
		WL("MMM : " + agora.ToString("MMM")); //Set
		WL("MMMM : " + agora.ToString("MMMM")); //Setembro
		
		//formato do ano
		WL("y : " + agora.ToString("y")); //Setembro de 2008
		WL("yy : " + agora.ToString("yy")); //08
		WL("yyyy : " + agora.ToString("yyyy")); //2008
		
		//horas
		WL("hh : " + agora.ToString("hh")); //07
		WL("HH : " + agora.ToString("HH")); //19
		
		//minutos
		WL("mm : " + agora.ToString("mm")); //45

		//segundos
		WL("ss : " + agora.ToString("ss")); //28
		WL("ff : " + agora.ToString("ff")); //04
		WL("fff : " + agora.ToString("fff")); //044
		WL("ffff : " + agora.ToString("ffff")); //0446
		WL("fffff : " + agora.ToString("fffff")); //04463 ...
		
		//outros
		WL("gg : " + agora.ToString("gg")); //D.C.
		WL("tt : " + agora.ToString("tt")); // (deveria ser PM)
		WL("zz : " + agora.ToString("zz")); //+01
		WL("zzz : " + agora.ToString("zzz")); //+01:00
		
		//toString parametrizados e separadores
		WL("HH:mm:ss:ffff : "+ agora.ToString("HH:mm:ss:ffff")); //19:43:25:0446
		WL("dd/MM/yyyy : "+ agora.ToString("dd/MM/yyyy")); //02/09/2008
		WL("dd 'de' MM em yyyy : "+ agora.ToString("dd 'de' MM 'em' yyyy 'às' HH e mm")); //02 de 09 em 2008 às 19 e 43
		WL(agora.ToString("dd-MM-yyyy HH:mm:ss"));	//02-09-2008 19:43:28
		
	}

Naturalmente, dada a especificidade dos nomes dos dias e meses, e mesmo a formatação das horas, os valores retornados pelo ToString() depende fortemente do da informação de cultura definido no System.Globalization do sistema onde corre as instruções. Este caso é para Português de Portugal.

Revendo o exemplo:

  • Sem parmetro de formatação, obtemos um valor de data e hora perfeitamente valido para uso comum.
  • Existe um conjunto de caracteres singulares que produzem uma data e hora completa. Dessas, apenas o ‘s’ e o ‘u’ produzem saídas ordenáveis.
  • O ‘U’ tem comportamento estranho e deve ser evitado.
  • Os componentes individuais tem diversas formatações possíveis, dependendo do número de vezes que o caracter é usado.
  • ‘f’ representa fracções de segundo. Cada ‘f’ acrescentado representa uma casa decimal extra na representação
  • É muito importante não confundir ‘M’ de meses com ‘m’ de minutos. É um erro que nem sempre é fácil de detectar ou cujo resultado é evidentemente errado.
  • É possível combinar os parâmetros de modo a criar novos que nos sirvam. Como separadores, podem ser usados o mais diversos caracteres, como espaços, dois pontos, barras, ou palavras. No caso de palavras, quando contem caracteres já definidos para formatação (como o ‘d’, o ‘m’, etc.) é importante envolver o(s) caracter(es) em aspas como ‘às’. Basta envolver caracter crítico (como à’s’) mas é mais legível envolver a palavra completa.

E assim fica. Para consultar mais info sobre o assunto, o Steve Tibbett tem no blog uma página dedicado a formatação com strings, incluindo outros tipos de dados, e há sempre a documentação da MSDN.