IIS/ASP.NET Cookieless Support Not Working As Expected
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
| Raw URL |
/Cookieless/(S({0861e55a-e29b-4b6f-825b-1e1d4c57f095}))/default.aspx |
Cookiless Cookies
AspFilterSessionId Request HTTP Header |
|
| Session ID |
{0861e55a-e29b-4b6f-825b-1e1d4c57f095} |
Eh lá! O que é que se passou aqui?
Parece que o IIS não conseguiu transferir os cookies para o header HTTP apropriado mas ASP.NET conseguiu encontrar o recurso pedido. Por outro lado, o IIS não conseguiu encontrar o ficheiro http://localhost/Cookieless/(S(%7b0861e55a-e29b-4b6f-825b-1e1d4c57f095%7d))App_Themes/Default/Styles.css.
Isto acontece em todos estes ambientes:
| Operating System |
IIS |
ASP.NET |
| Windows XP Pro SP3 |
5.1 |
2.0 SP1, 3.5 |
| Windows Server 2003 R2 |
6 |
2.0 SP1, 3.5 |
| Windows Server 2008 |
7 |
2.0 SP1, 3.5 |
Felizmente, com o IIS 7 podem-se definir módulos HTTP quando em modo integrated pipeline que serão executados para todos os pedidos feitos ao IIS.
O módulo nem precisa de fazer nada. Apenas precisa de existir:
public class Module : System.Web.IHttpModule
{
public void Dispose()
{
}
public void Init(System.Web.HttpApplication context)
{
}
}
e ser adicionado à configuração:
<configuration>
<system.web>
<sessionState cookieless="UseUri" sessionIDManagerType="SessionIdManager" />
<pages theme="Default"/>
</system.web>
<system.webServer>
<modules>
<add name="Module" preCondition="integratedMode" type="Module" />
</modules>
</system.webServer>
</configuration>
E a nossa “linda” página está de volta:
| Raw URL |
/Cookieless/default.aspx |
Cookiless Cookies
AspFilterSessionId Request HTTP Header |
S({0861e55a-e29b-4b6f-825b-1e1d4c57f095}) |
| Session ID |
{0861e55a-e29b-4b6f-825b-1e1d4c57f095} |
Sou só eu a pensar isto, ou há aqui qualquer coisa errada?
Foi por isso que submeti este erro no Microsoft Connect