Allora, dopo i due post di introduzione della problematica e di descrizione di tutte le possibili implementazioni, ecco la conclusione sull'argomento.
Abbiamo detto che per inserire il contenuto del ViewState al di fuori della pagina aspx abbiamo tre possibilità:
- utilizzare il filesystem
- utilizzare la sessione
- utilizzare la cache della pagina
Mi sono quindi creato un'enumeration per darmi la possibilità di effettuare la scelta:
namespace Peppe.Web.UI
{
public enum ViewStateLocation
{
///<summary>Leaves the viewstate ones its place.</summary> Default,
///<summary>Sets view state saved on page cache.</summary> Cache,
///<summary>Sets view state saved on session.</summary> Session,
///<summary>Sets view state saved on filesystem.</summary> FileSystem
}
}
e sono andato a creare una nuova classe che erediti dalla classe Page.
A questa classe ho aggiunto la proprietà ViewStateLocation, per settare il tipo di tecnica da utilizzare per salvare il viewstate, e le proprietà ViewStateDirectory e ViewStateFilePath, utili per l'archiviazione del viewstate sul filesystem. Infine ho fatto l'overload dei metodi LoadPageStateFromPersistenceMedium e SavePageStateToPersistenceMedium e ci ho inserito dentro il codice necessario ad implementare tutte le tecniche descritte.
protected override object LoadPageStateFromPersistenceMedium()
{
switch(this.ViewStateLocation)
{
case ViewStateLocation.Cache:
{
LosFormatter formatter = new LosFormatter();
string str = Request.Form["__VIEWSTATE_KEY"];
if (!str.StartsWith("VIEWSTATE_"))
{
throw new Exception("Invalid viewstate key:" + str);
}
object vs = Cache[str];
if(vs != null)
return formatter.Deserialize(vs.ToString());
else
return null;
}
case ViewStateLocation.Session:
{
LosFormatter formatter = new LosFormatter();
object vs = Session["state"];
if (vs!=null)
return formatter.Deserialize(vs.ToString());
else
return null;
}
case ViewStateLocation.FileSystem:
{
string vsString = Request.Form[ViewStateHiddenFieldName];
if (!File.Exists(vsString))
throw new Exception("The Viewstate file " + vsString + " is missing.");
else
{
LosFormatter formatter = new LosFormatter();
StreamReader sr = File.OpenText(vsString);
string viewStateString = sr.ReadToEnd();
sr.Close();
return formatter.Deserialize(viewStateString);
}
}
default:
{
return base.LoadPageStateFromPersistenceMedium();
}
}
}
protected override void SavePageStateToPersistenceMedium(object viewState)
{
switch(this.ViewStateLocation)
{
case ViewStateLocation.Cache:
{
LosFormatter formatter = new LosFormatter();
StringWriter writer = new StringWriter();
string str = "VIEWSTATE_" + Request.UserHostAddress + "_"
+ DateTime.Now.Ticks.ToString();
formatter.Serialize(writer, viewState);
Cache.Add(str, writer.ToString(), null,
DateTime.Now.AddMinutes(Session.Timeout),TimeSpan.Zero,
CacheItemPriority.Default, null);
writer.Close();
RegisterHiddenField("__VIEWSTATE_KEY", str);
break;
}
case ViewStateLocation.Session:
{
StringWriter writer = new StringWriter();
LosFormatter formatter = new LosFormatter();
formatter.Serialize(writer, viewState);
string state = writer.ToString();
writer.Close();
Session["state"] = state;
break;
}
case ViewStateLocation.FileSystem:
{
LosFormatter formatter = new LosFormatter();
StringWriter writer = new StringWriter();
formatter.Serialize(writer, viewState);
StreamWriter sw = File.CreateText(this.ViewStateFilePath);
sw.Write(writer.ToString());
sw.Close();
writer.Close();
Page.RegisterHiddenField(ViewStateHiddenFieldName, ViewStateFilePath);
break;
}
default:
{
base.SavePageStateToPersistenceMedium(viewState);
break;
}
}
}
Fatto questo, non resta altro che ereditare le nostre classi di code-behind delle nostre pagine .aspx, dalla classe che abbiamo appena definito e non dalla classe Page, e assegnare un valore alla variabile ViewStateLocation.
public class myASPXpage : Peppe.Web.UI.Page
{
public void Page_Load(object sender, System.EventArgs e)
{
this.ViewStateLocation = Peppe.Web.UI.ViewStateLocation.Session;
}
}
E con questo post chiudo l'argomento :)