Eu acho a classe System.Web.HttpValueCollection muito útil num vasto número de situações que envolvem a composição de pedidos HTTP ou qualquer outra necessidade e representar uma colecção de pares nome/valor como uma cadeia de caracteres (num atributo XML, por exemplo).
Actualmente (.NET Framework 3.5 SP1 Beta), a única forma de criar uma instância da classe System.Web.HttpValueCollection é usando o método System.Web.HttpUtility.ParseQueryString.
Eu gostaria que esta classe fosse pública e estivesse numa assembly mais genérica como a System.DLL para estar disponível para qualquer tipo de aplicação .NET (aplicações Windows Client, aplicações Windows Service, aplicações Silverlight, aplicações Windows Mobile, etc.).
Se concordam comigo, votem na minha sugestão no Microsoft Connect.
Se executarem este código:
System.Collections.Specialized.NameValueCollection queryString = System.Web.HttpUtility.ParseQueryString("noKey&=emptyKey&A=Akey");
queryString será, na verdade, uma referência para uma instância do tipo System.Web.HttpValueCollection.
O que esta classe tem de bom é que o resultado da chamada ao método ToString é o conteúdo da colecção devidamente codificado e formatado para ser usado num URL.
Tal como acontece com a classe base (NameValueCollection), há uma diferença entre a chave ser uma cadeia (string) nula ou uma cadeia vazia na forma como é feita a interpretação da cadeia de entrada. Uma cadeia nula corresponde a não ser especificado parâmetro e uma cadeia vazia corresponde a ser especificado um parâmetro cujo nome é uma cadeia vazia.
Sendo assim, quando se chama ToString numa instância retornada pelo método System.Web.HttpUtility.ParseQueryString espera-se obter a cadeia de entrada (ou, pelo menos, uma que, quando interpretada, dê origem a uma colecção equivalente), certo? Na verdade, o que se obtém é isto: noKey&emptyKey&A=Akey.
Reportei este erro no connect. Se acham que é importante e deve ser corrigido, votem.
Está aí o SAPO Summerbits, 1ª Edição.
O programa "SAPO Summerbits” é inspirado no Google Summer of Code, onde são oferecidas bolsas a estudantes, de todos os graus de ensino ou proveniências (maiores de 18 anos e com vínculo a escola/universidade portuguesa), para que desenvolvam código para projectos de software livre, já existentes ou completamente novos. O SAPO, com o apoio de outras entidades, seleccionará as ideias com maior impacto tecnológico e social, financiando o seu desenvolvimento ao longo de três meses. A ambição do SAPO Summerbits é, acima de tudo, a de se tornar um programa de referência no meio académico português, mostrando ao mundo toda a capacidade criativa dos nossos estudantes.
Hoje, a Typemock lançou a versão 4.3 do Typemock Isolator. Descarreguem daqui.
O que há de novo?
- Suporte para Ivonna. Para quem desenvolve aplicações ASP.NET, o Ivonna é uma grande ferramenta, suportada pela plataforma Isolator, para simplificar a escrita de testes para ASP.NET.
- Adição e APIs do namespace Typemock.Integration.Packs para gestão de licenças através do Isolator, como usa o Ivonna.
- Tal como tinha sido anunciado quando foi lançada, a versão 4.2 foi a última a suportar .NET 1.1. A versão 4.3 suporta apenas o ambiente de execução 2.0 e respectivas versões de Visual Studio: VS2005 e VS2008.
- Para máquinas de 64 bit, agora existe apenas um instalador. (não esquecer desinstalar ambas as versões anteriores (32 e 64 bit) antes de instalar a versão 4.3.)
- RecorderManager.GetMockOf(instanceRef) e MockManager.GetMockOf(instanceRef). Para o objecto controlador do objecto simulado (mock) a partir de uma instância de objecto simulado. (mais...).
Problemas resolvidos:
- Problemas no suporte a DLINQ resolvidos.
- Os construtores estáticos já são invocados correctamente quando se usa Natural Mocks.
- Resolvido o problema em que era lançada uma excepção quando se simulavam interfaces ("Method XX in type IMyInterface has no matching overload that returns TypeMock.Mock+a).
- Resolvido o problema em que era lançada uma excepção quando o objecto simulado sobrepunha uma implementação de Equals.
- Resolvido o problema que causava falhas na simulação de implementação explicita de interface com o mesmo nome.
- Resolvido o problema com VerifyWithWait em cenários de multithreading.
- Resolvido o problema em que era lançada uma NullReferenceException quando se usava Auto Deploy.
Mais informações:
Numa entrada anterior mencionei a minha biblioteca para geração de valores aleatórios para efeitos de testes unitários.
Recebi alguns comentários e questões interessantes nos meus blogues [^][^][^][^].
O Simon diz que ele “geralmente quer que cada instância do teste que corre seja repetível em *todas* as execuções” e está “inclinado a usar a funcionalidade de fonte de dados do VSTS Unit Tests”. Eu não podia estar mais de acordo.
O Hugo indicou-me o Pex. Parece interessante. Tenho de ver melhor isto.
Alguns comentários mostravam alguma preocupação para, no caso do teste falhar, não ser possível reproduzir as condições do teste e por isso não seria possível perceber a razão da falha do teste. Na minha opinião, todos os dados usados num teste que falha devem estar no relatório do teste (pelo menos, os dados que fizeram o teste falhar). Quer os dados sejam previsíveis ou aleatórios.
Acho que a maioria dos comentários “contra” a minha ideia se deveram ao facto de não a ter explicado bem. Vou tentar fazer melhor agora.
Eu uso estes valores aleatórios quando o valor em si não é importante, apenas o facto de ser único.
Imagine-se uma classe Cliente em que para dizer que duas instâncias se referem ao mesmo cliente é suficiente comparar o seu ID. Para testar o código e comparação não necessito nenhum conjunto reprodutível de dados. Apenos preciso que sejam difrentes ou mesmo, dependendo do teste.
Imagine-se que se está a testar código de acesso a base de dados com uma connection string de um elemento específico de connection string settings. Não é importante saber qual o conteúdo da connection string porque não se vai realmente aceder à base ded dados (isto é muito fácil de fazer com o Isolator).
Espero ter-me explicado melhor desta vez.
Recentemente perguntaram-me se era possível substituír as assemblies carregadas por uma aplicação Windows Service implementada em .NET enquanto esta corre, como o ASP.NET. Tal como no ASP.NET, eventos de início e de fifinalização da aplicação eram necessários.
A solução até é simples. A aplicação Windows Service passa a ser apenas um carregador que não tem qualquer referência para as assemblies carregadas que poderão sofrer alterações e ter uma assembly com um ponto de entrada que funciona como o evento de início. Esta assembly deve ser carregada num novo AppDomain com ShadowCopyFiles definido como true. O evento de finalização é tratado tratando o evento DomainUnload do AppDomian onde as assemblies a correr foram carregadas.
Se se quiser que a assembly a correr, assim como as assemblies por esta referenciadas sejam descarregadas e novamente carregadas quando ocorre uma modificação nos ficheiros destas assemblies, pode-se recorrer a um FileSystemWatcher, embora eu preferisse anular este comportamento no ASP.NET, não copiá-lo.
O carregador pode ser algo tão simples como isto:
class Program
{
private static Thread thread = null;
private static AppDomain appDomain = null;
static void Main(string[] args)
{
while (true)
{
Console.WriteLine();
Console.WriteLine("Options:");
if (appDomain == null)
{
Console.WriteLine(" L - Load");
}
else
{
Console.WriteLine(" U - Unload");
}
Console.WriteLine(" X - Exit");
switch (Console.ReadKey().KeyChar)
{
case 'l':
case 'L':
thread = new Thread(Load);
thread.Name = "Runner";
thread.Start(args);
while (appDomain == null) ;
break;
case 'u':
case 'U':
Unload();
break;
case 'x':
case 'X':
Unload();
return;
}
}
}
private static void Load(object obj)
{
string[] args = obj as string[];
AppDomainSetup appDomainSetup = new AppDomainSetup();
appDomainSetup.ApplicationBase = args[0];
appDomainSetup.PrivateBinPath = args[0];
appDomainSetup.ShadowCopyFiles = "true";
appDomain = AppDomain.CreateDomain("Runner", AppDomain.CurrentDomain.Evidence, appDomainSetup);
appDomain.ExecuteAssemblyByName("ConsoleApplication", AppDomain.CurrentDomain.Evidence, new string[0]);
}
private static void Unload()
{
AppDomain.Unload(appDomain);
appDomain = null;
thread = null;
}
}
O carregador recebe o caminho para a pasta onde estão as assemblies a carregar e o nome da assembly a correr.
A assembly a correr pode ser algo com isto:
class Program
{
static readonly DateTime dateTime = DateTime.Now;
static void Main(string[] args)
{
AppDomain.CurrentDomain.DomainUnload += delegate
{
Console.WriteLine();
Console.WriteLine("Unloading: {0}", dateTime);
};
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
Console.WriteLine("Loading: {0}", dateTime);
Console.WriteLine("Assembly: {0}", assembly.FullName);
Console.WriteLine("Location: {0}", assembly.Location);
FileInfo fileInfo = new FileInfo(assembly.Location);
Console.WriteLine("Location Dates: CreationTime={0}, LastWriteTime={1}, LastAccessTime={2}",
fileInfo.CreationTime, fileInfo.LastWriteTime, fileInfo.LastAccessTime);
while (true)
{
Console.Write('.');
Thread.Sleep(100);
}
}
}
Com este “sistema” pode-se carregar ou descarregar e substituír as assemblies que estão a correr quando se quiser.
Quando escrevo os meus testes unitários não gosto de usar valores fixos no código porque ou acabo por usar sempre os mesmos valores ou, por causa disso, os testes podem passar por coincidência.
Com o passar do tempo, desenvolvi uma classe utilitária para gerar valores aleatórios para usar em testes unitários.
namespace PauloMorgado.VisualStudio.TestTools.UnitTesting
{
public static class RandomGenerator
{
public static bool Boolean();
public static string String();
public static string String(string prefix);
public static short Int8();
public static short Int8(short maxValue);
public static short Int8(short minValue, short maxValue);
public static short Int16();
public static short Int16(short maxValue);
public static short Int16(short minValue, short maxValue);
public static int Int32();
public static int Int32(int maxValue);
public static int Int32(int minValue, int maxValue);
public static TEnum Enum<TEnum>();
public static TEnum EnumFlagsWith<TEnum>(TEnum flagsToAdd);
public static TEnum EnumFlagsWithout<TEnum>(TEnum flagsToRemove);
public static TEnum Enum<TEnum>(int maxValue);
public static TEnum Enum<TEnum>(int minValue, int maxValue);
public static System.Guid Guid();
}
}
Isto é algo que eu gostaria de ver em plataformas de mocks (como Typemock Isolator, Rhino.Mocks ou MoQ).
Ainda é um trabalho em curso, mas se quiserem testar, está na minha MSDN Code Gallery: Random Generator For Unit Testing
Em entradas anteriores [^][^] comentei a dimensão da tradução para HTML dos validadores e sumário de validadores do ASP.NET e o facto de serem usados expando attributes para a tradução das propriedades. O Mohamed também comenta esta questão.
Além de não estarem em comformidade com o XHTML, o tratamento do Firefox para atributos prórprios difere do tratamento do Internet Explorer.
No Internet Explorer estes atributos são convertidos em propiedades do tipo string do elemento HTML. Já no Firefox, estes atributos são apenas acessíveis através da colecção attributes.
Pergunto-me porque será que não gosto de trabalhar com código cliente quando desenvolvo para web.
O Windows Home Server Power Pack 1 Release Candidate foi disponibilizado para testes públicos. Leiam tudo aqui.
Há alguns dias um colega indicou-me uma ferramenta (IETester) que permite testar diferentes motores de HTML e JavaScript do Internet Explorer (5.5, 6, 7 e 8beta1) lado a lado com a versão instalada.
Ainda não testei o IETester, mas encontrei duas outras ferramentas que me chamaram à atenção: DebugBar e Companion.JS.
A DebugBar é como outras ferramentas que uso [^] com algumas diferenças. A DebugBar é uma barra lateral do Internet Explorer e não pode ser separada deste, mas tem uma consola de JavaScript e rastreia o tráfego HTTP/HTTPS que pertence à tab (IE 7) visível. Também consegue inspeccionar outras instâncias de Internet Explorer como o Document Explorer ou o FeedDemon.
A Companion.JS é uma ferramenta do tipo do Firebug e foi a que mais me agradou porque me deu algo que eu não tinha: algo que me livrasse dos incómodos diálogos de erros de script.
Tanto a DebugBar como a Companion.JS alegam ser debuggers de JavaScript mas não encontrei nenhum modo de definir breakpoints ou correr scripts paço a paço. Provavelmente porque tenho o Visual Studio instalado esta máquina.
O registo para o Microsoft Tech-Ed EMEA 2008 está aberto.

Notem que, este ano, o evento para IT Professionals acontece antes do evento para Developers.
Tomei conhecimento, através do <