A Microsoft Press criou um URL exclusivo para um desconto na subscrição da E-Reference Library para os MVPs passarem à comunidade, sem quaisquer limitações ou restrições.
Para criar uma subscrição experimental, deve ser usado o URL Experimental (http://microsofteref2.books24x7.com/promo.asp?ref=mvptry).
Qualquer membro da comunidade que subscreva a E-Reference Libraries através do URL de Subscrição (http://microsofteref2.books24x7.com/promo.asp?ref=mvpbuy) terá direito a um desconto de 40% numa subscrição de um ano.
Esta oferta termina a 30 de Setembro de 2008.
A equiopa do StyleCop anunciou a saída da versão 4.3 da ferramenta StyleCop. Podem obtê-la aqui.
Esta versão contem algumas correcções de erros, novas regras e documentação.
Também nesta versão, a lista de erros e avisos vai para a janela Errors List como acontece com os compiladores. Gostava que os erros e avisos também fossem para a janela Output.
A documentação do SDK para o desenvolvimento de regras próprias e integração com outros sistemas de build é esperada para breve.
Convenhamos, quem não conhece o .NET Reflector não pode afirmar que desenvolve em .NET.
Hoje, a Red Gate anunciou a aquisição do Lutz Roeder’s .NET Reflector.
Na nova página do .NET Reflector, a Red Gate afirma que “continuará a manter uma versão gratuita para o benefício da comunidade”.
Podem ler a entrevista com Lutz Roeder e James Moore (director geral de ferramentas de desenvolvimento .NET da Red Gate) na simple-talk.
O James ainda não sabe como melhorar o Reflector, mas eu sei. O Reflector necessita de importantes melhoramentos ao nível da usabilidade da interface com o utilizador. Vejamos se consigo arranjar uma lista:
- Para mim, a pesquisa enquanto se digita não é uma boa ideia tal como está no Reflector.
- Ainda no tema da pesquisa, pesquisa enquanto se digita já seria uma boa ideia para a janela de código.
- Não consigo perceber porque mudar alguma opção dispara um refrescamento total da aplicação perdendo-se a janela de código.
- Definições como a formatação de código, documentação ou números deveria ser possível apenas com o simples premir de um botão numa barra de botões.
Tenho a certeza que a Red Gate é mais do que capaz de tomar bem conta do .NET Reflector.
A Typemock lançou uma versão alfa do seu mais recente produto: Typemock Racer.
O Typemock Racer é a ferramenta que usa análise dinâmica e estática para encontrar bloqueios em código .NET que tinha sido anuncianda pelo Roy Osherove.
A Typemock lançou a versão 5.0 da sua ferramenta de testes unitários: Isolator. Vejam as notas de lançamento.
Esta mais recente versão vem com a nova API: Arrange Act Assert (Preparar – Executar - Validar):
Devo dizer que gostava mais de Isolator do que Isolate.
Também novidade nesta versão é a inclusão do ficheiro de ajuda no pacote de instalação.
Enquanto instalava o SQL Server 2008 numa máquina virtual Virtual PC, fiquei sem espaço no disco virtual.
Pesquisei e encontrei esta ferramenta: VHD Resizer. É necessário registo para descarregar a ferramenta.
No passado apresentei um outro possível uso para a palavra-chave using: como dicas LINQ.
Tenhno vindo a pensar mais neste assunto e refinei a minha proposta.
var q = from person in personCollection using MyEnumerableExtensions
group person by person.LastName into g using new MyOtherComparer()
orderby g.Key using new MyComparer()
select person;
A consulta acima seria traduzida para:
var q = MyEnumerableExtensions.OrderBy<string, Person>(
MyEnumerableExtensions.GroupBy<string, Person>(
personCollection,
person => person.LastName,
new MyComparer(),
),
g => g.Key,
mew MyOtherComparer()
);
O que acham disto?
O C# 3.0 introduziu inicializadores de object and collection. É agora possível criar objectos e colecções pré-inicializados:
var person = new Person { FirstName = "Paulo", LastName = "Morgado" };
var persons = new List<Person> {
new Person { FirstName = "Paulo", LastName = "Morgado" },
new Person { FirstName = "Luís", LastName = "Abreu" }
};
var personDirectory = new Dictionary<string, Person> {
{ "Lisboa", new Person { FirstName = "Paulo", LastName = "Morgado" } },
{ "Funchal", new Person { FirstName = "Luís", LastName = "Abreu" } }
};
Não era bom podermos fazer o mesmo para objectos e colecções já existentes?
Que sintaxe seria usada? Algo deste género?
var person = new Person();
person = { FirstName = "Paulo", LastName = "Morgado" };
var persons = new List<Person>();
persons += {
new Person { FirstName = "Paulo", LastName = "Morgado" },
new Person { FirstName = "Luís", LastName = "Abreu" }
};
var personDirectory = new Dictionary<string, Person>();
personDirectory += {
{ "Lisboa", new Person { FirstName = "Paulo", LastName = "Morgado" } },
{ "Funchal", new Person { FirstName = "Luís", LastName = "Abreu" } }
};
O que pensam disto?
De acordo com a página inicial das MSDN Subscriptions, devemos esperar que o Service Pack 1 do Visual Studio 2008 esteja disponível após o próximo dia 11 de Agosto de 2008.

Finalmente está aí o SQL Server 2008 e vem com a Entity Framework, o que quer dizer que o SP1 para o Visual Studio 2008 e a .NET Framework também deve estar a saír.
O ASP.NET disponibiliza três tipos de armazenamento de estado de sessao:
| Provider | Description |
| InProc | O estado de sessão é armazenado no cache ASP.NET. |
| SQLServer | O estado de sessão é armazenado numa base de dados SQL Server. |
| StateServer | O estado de sessão é armazenado é armazenado num serviço de armazenamento de estado. |
Porque com o SQLServer e o StateServer o estado tem de atravessar a fronteira do AppDomain, tem de ser seriado antes de ser armazenado e desseriado quando carregado. Porque o estado tem de ser carregado e armazenado em cada pedido, só está disponível desde o evento PostAcquireRequestState até ao evento ReleaseRequestState. E, devido à seriação e desseriação, todos os objectos armazenados têm de ser seriáveis e qualquer referência mantida para um item do estado não será para o mesmo item após a desseriação do estado.
Por outro lado, com o InProc, o estado nunca será seriado ou desseriado, o que quer dizer que os objectos não necessitam de ser seriáveis e qualquer referência para um item do estado será sempre uma referência para um item do estado mesmo antes do evento PostAcquireRequestState e após o evento ReleaseRequestState.
Na prática, durante o desenvolvimento é usado o InProc e em produção é usado o SQLServer. Isto leva, muitas vezes, a erros aplicacionais que apenas se manifestam em ambiente de produção, com armazenar objectos não seriáveis no estado. Foi por isso que escrevi um provedor de armazenamento de estado em memória que seria e desseria os itens armazenados. Podem obter o código fonte aqui.
(Isto foi-me referido pelo Frans Bouma e explicado pelo Jon Skeet)
Imaginem este conjunto de classes:
public class A
{
public virtual string P
{
get { return "A"; }
}
}
public class B : A
{
}
public class C : B
{
public override string P
{
get { return "C"; }
}
}
E esta classe:
public static class Reporter
{
public static void Report<T>(T target, Expression<Func<T, string>> expression)
{
Console.WriteLine("Expression: {0}", expression);
Console.WriteLine("\tDeclaring Type: {0}", ((expression as LambdaExpression).Body as MemberExpression).Member.DeclaringType);
Console.WriteLine("\tInvocation Result: {0} for {1}", expression.Compile().Invoke(target), target.GetType());
Console.WriteLine();
}
}
A classe acima escreve na consola a expressão Lambda, o tipo que declara a propriedade e o valor da propridedade para target e o tipo de target.
Vejamos o que acontece quando é usado o seguinte código C#:
Reporter.Report(new C(), (A a) => a.P);
Reporter.Report(new C(), (B b) => b.P);
Reporter.Report(new C(), (C c) => c.P);
Reporter.Report(new B(), (A a) => a.P);
Reporter.Report(new B(), (B b) => b.P);
Reporter.Report(new A(), (A a) => a.P);
O resultado será:
Expression: a => a.P
Declaring Type: A
Invocation Result: C for C
Expression: b => b.P
Declaring Type: A
Invocation Result: C for C
Expression: c => c.P
Declaring Type: A
Invocation Result: C for C
Expression: a => a.P
Declaring Type: A
Invocation Result: A for B
Expression: b => b.P
Declaring Type: A
Invocation Result: A for B
Expression: a => a.P
Declaring Type: A
Invocation Result: A for A
Por outro lado, se for usado o seguinte código Visual Basic:
Reporter.Report(New C(), Function(a As A) a.P)
Reporter.Report(New C(), Function(b As B) b.P)
Reporter.Report(New C(), Function(c As C) c.P)
Reporter.Report(New B(), Function(a As A) a.P)
Reporter.Report(New B(), Function(b As B) b.P)
Reporter.Report(New A(), Function(a As A) a.P)
O resultado será:
Expression: a => a.P
Declaring Type: A
Invocation Result: C for C
Expression: b => b.P
Declaring Type: A
Invocation Result: C for C
Expression: c => c.P
Declaring Type: C
Invocation Result: C for C
Expression: a => a.P
Declaring Type: A
Invocation Result: A for B
Expression: b => b.P
Declaring Type: A
Invocation Result: A for B
Expression: a => a.P
Declaring Type: A
Invocation Result: A for A
Porquê as diferenças? Por causa das diferenças nas especificações e compiladores das diferentes inguagens:
- O compilador de C# gerará uma chamada virtual ao membro virtual na classe em que é declarado como virtual.
- O compilador de Visual Basic gerará uma chamada virtual ao membro sobreposto na classe em que é implementado.
Num dos ambientes em que trabalho não podem ser utilizados cookies porque as páginas correm em controlos web browser hospedados numa aplicação cliente e os cookies acabam por ser partilhados entre todos os browsers.
Felizmente, o ASP.NET permite-nos persistir alguns cookies como parte do URL.
Para persistir o cookie do identificador do estado de sessão no URL basta adicionar a seguinte configuração:
<configuration>
<system.web>
<sessionState cookieless="UseUri" />
</system.web>
</configuration>
e obtemos URLs destes:
http://localhost/Cookieless/(S(jcmwek3ja0lvdpbwoacpjirv))/default.aspx
O modo como o IIS e o ASP.NET fazem isto é através da remoção da secção entre parentesis por parte do IIS e a adição do valor removido como um header HTTP de nome AspFilterSessionId ao pedido. Em seguinda, o ASP.NET extrai o cookie desse header HTTP.
Fiz esta página simples para demonstrar o funcionamente desta funcionalidade:
<%@ Page Language="C#" AutoEventWireup="true" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<table>
<tr>
<td>Raw URL</td>
<td><%= Request.RawUrl %></td>
</tr>
<tr>
<td>Cookiless Cookies<br />AspFilterSessionId Request HTTP Header</td>
<td><%= Request.Headers["AspFilterSessionId"] %></td>
</tr>
<tr>
<td>Session ID</td>
<td><%= Session.SessionID %></td>
</tr>
</table>
</div>
</form>
</body>
</html>
Para o URL acima, obtemos a seguinte página:
| Raw URL |
/Cookieless/default.aspx |
Cookiless Cookies
AspFilterSessionId Request HTTP Header |
S(jcmwek3ja0lvdpbwoacpjirv) |
| Session ID |
jcmwek3ja0lvdpbwoacpjirv |
O IIS também efectua esta operação para os conteúdos estáticos como folhas de estilos.
Para o testar podemos adicionar um tema. Isto pode ser conseguido adicionando uma pasta Default abaixo da pasta App_Themes e adicionando-lhe o ficheiro Styles.css:
body
{
background-color: Yellow;
}
table, tr, td
{
border: thin solid black;
}
e definindo o tema como tema predefinido através da eguinte configuração:
<configuration>
<system.web>
<sessionState cookieless="UseUri" />
<pages theme="Default"/>
</system.web>
</configuration>
E, de repenete, a nossa página fica mais “bonita”:
| Raw URL |
/Cookieless/default.aspx |
Cookiless Cookies
AspFilterSessionId Request HTTP Header |
S(jcmwek3ja0lvdpbwoacpjirv) |
| Session ID |
jcmwek3ja0lvdpbwoacpjirv |
Se, por alguma razão, necessitamos de providenciar os nossos próprios identificadores de sessão, podemos implementar o nosso próprio gestor de identificadores de sessão.
Mas, se queremos tirar partido dos cookieless cookies, só há um modo: extender a classe SessionIDManager:
public class SessionIdManager : System.Web.SessionState.SessionIDManager
{
public override string CreateSessionID(System.Web.HttpContext context)
{
string id = System.Guid.NewGuid().ToString("B");
return id;
}
public override bool Validate(string id)
{
try
{
new System.Guid(id);
return true;
}
catch
{
return false;
}
}
}
e configura o sistema de estado e sessão para o usar:
<configuration>
<system.web>
<sessionState cookieless="UseUri" sessionIDManagerType="SessionIdManager" />
<pages theme="Default"/>
</system.web>
</configuration>
E obtemos esta simpática página:
http://localhost/Cookieless/(S(%7b0861e55a-e29b-4b6f-825b-1e1d4c57f095%7d))/default.aspx