In ASP.NET 2.0 l'uso dei DataSourceControl risparmia tempo e
codice in quanto questi controlli si occupano di gestire autonomamente le
operazioni
più comuni di data binding.
Per
esempio nella pagina non è più necessario dover invocare il metodo DataBind sul
controllo che lo usa.
L'ObjectDataSource
ci permette di effettuare il data binding utilizzando metodi invece che sintassi
SQL.
Questo ci permette di continuare a lavorare con il nostro strato di
business o di accesso ai dati e di avere allo stesso tempo il vantaggio d'uso di
un controllo simile.
Detto questo,
non è tutto oro quello che luccica.
Sappiamo che
l'ObjectDataSource utilizza reflection per invocare i metodi sul tipo
specificato.
Quindi quando per esempio la GridView avrà bisogno di effettuare
"data bind", passerà la chiamata all' ObjectDataSource associato il quale
istanzierà il tipo contenente il metodo di Select, invocandolo a sua
volta.
Se siamo
curiosi, con Reflector è possibile andare a vedere come funziona il
tutto.
Nei
casi meno "demo-oriented" è utile poter decidere che il metodo di Select e
SelectCount stiano direttamente all'interno della pagina aspx che ospita i
controlli.
Questo dal
momento che potrei aver bisogno di effettuare ordinamenti o filtri che non posso
incapsulare come parametri del metodo di Select.
Possiamo configurare l'ObjectDataSource in modo che il
metodo di Select specificato stia nella pagina.Ma se ci mettiamo a debug nel
metodo stesso, possiamo notare che quando viene invocato il contesto "this" è si
la pagina stessa,
ma completamente vuota.
Questo perchè,
come spiegato prima, l'ObjectDataSource crea l'istanza e poi invoca il
metodo.Quindi è più che corretto trovarsi l'istanza vuota.
Per
risolvere il problema allora possiamo utilizzare un nostro custom
ObjectDataSource, che qui ho chiamato SmartObjectDatasource.
Questo non fa
nient'altro che intercenttare l'evento di creazione dell'istanza e modificare
l'istanza stessa:
public class SmartObjectDataSource : ObjectDataSource
{
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
this.ObjectCreated += new ObjectDataSourceObjectEventHandler(SmartObjectDataSource_ObjectCreated);
}
void SmartObjectDataSource_ObjectCreatedobject sender, ObjectDataSourceEventArgs e)
{
if (e.ObjectInstance is System.Web.UI.Page)
{
((System.Web.UI.Page)e.ObjectInstance) =
this.Page;
}
}
}
Cosi facendo quando il metodo di Select sarà invocato, noi saremo sicuri che
"this" corrisponderà alla pagina vera e propria, con tutti i dati
caricati(session, form, viewstate, controlli, etc...).
Per chi usa ATLAS per incapsulare all'interno di un UpdatePanel il controllo
che usa lo SmartObjectDataSource ci sono alcuni problemi.
Infatti in questo
caso la pagina non riesce più ad eseguire il rendering parziale e ci troviamo di
fronte al classico postback, nonostante tutto(lato ATLAS) sia configurato
per bene.
Il problema è dovuto a questa riga
((System.Web.UI.Page)e.ObjectInstance) = this.Page;
Per ovviare al
problema è sufficiente modificare il codice dello SmartObjectDataSource in
questo modo:
public class SmartObjectDataSource : ObjectDataSource
{
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
this.ObjectCreated += new ObjectDataSourceObjectEventHandler(SmartObjectDataSource_ObjectCreated);
}
void SmartObjectDataSource_ObjectCreated
object sender, ObjectDataSourceEventArgs e)
{
if (e.ObjectInstance is System.Web.UI.Page)
{
((System.Web.UI.Page)e.ObjectInstance).Items.Add("PageInstance", this.Page);
}
}
}
Nel metodo di Select nella pagina al posto di riferirsi a "this" per avere la
pagina, sarà sufficiente ricavarla in questo modo :
MyPageAspx page = (MyPageAspx)this.Items["PageInstance"];