I DataSource controls sono una delle novità di ASP.NET 2.0 e vanno a far parte della nuova architettura per il databinding dei dati, in quanto permettono l’utilizzo del databinding dichiarativo all'interno di pagine web.
Un DataSource control non è altro che un archivio di informazioni, che possono essere lette, modificate o cancellate attraverso l’esecuzione di metodi pre-confezionati. Quelli gia presenti all'interno del framework sono:- SqlDataSource – Che permette di prelevare informazioni da SqlServer
- AccessDataSource – Che permette di prelevare informazioni da Access
- ObjectDataSource – Che permette di prelevare informazioni da proprie collezioni di oggetti di business
- XmlDataSource – Che permette di prelevare informazioni da file xml
- SiteMapDataSource – Che permette di prelevare informazioni da file .sitemap
Ogni controllo di questo tipo, controlli che ereditano dalla classe DataSourceControl, può essere associato ad altri controlli per effettuare il DataBind dei dati attraverso la proprietà DataSourceID; tale proprietà è stata aggiunta nei controlli come il Repeater, la DataGrid, la DataList e la nuova GridView.
<asp:SiteMapDataSource id="ds" runat="server" />
<asp:Repeater id="rep" DataSourceID="ds" runat="server">
<ItemTemplate>
<%# Eval("Title") %><br />
</ItemTemplate>
</asp:Repeater>
Questo è ciò che il framework ci mette a disposizione di default; se invece, avessimo la necessità di creare dei controlli generici che prelevino informazioni da delle fonti di dati differenti da quelle gia supportate, dovremmo sfruttare i meccanismi di estensione che ASP.NET offre e implementare dei nostri DataSource control personalizzati.
Nell'esempio che vi propongo, andremo a creare un DataSource control per la lettura di feed Rss e Atom. L'esempio è abbastanza semplice, ma spiega alla perfezione i passi di base necessari per l'implementazione di DataSource control personalizzati.
Un DataSource control in realtà non fa tanto, in quanto tutta la logica relativa alla lettura o alla modifica delle informazioni è lasciata ad un oggetto derivato dalla classe DataSourceView. Tale classe deve obbligatoriamente implementare i meccanismi di SELECT dalla fonte di dati, e può decidere di implementare o meno quelli di UPDATE, INSERT e DELETE.
La classe che eredita da DataSourceControl avrà invece la definizione di tutte le proprietà utili a rendere il controllo il più dinamico possibile.
Vediamo ora il codice delle due classi (l'implementazione di alcune classi o metodi ridondanti sarà omessa, ma comunque presente nell’applicazione d’esempio da scaricare):
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
namespace Peppe.Web.UI.WebControls
{
public class FeedDataSource : DataSourceControl
{
private FeedDataSourceView view;
public static readonly string ViewName = "View";
public FeedType FeedType
{
get
{
if (ViewState["FeedType"] != null)
return (FeedType)ViewState["FeedType"];
else
return FeedType.Rss;
}
set
{
ViewState["FeedType"] = value;
View.RaiseChangedEvent();
}
}
public string FeedUrl
{
get
{
if (ViewState["FeedUrl"] != null)
return (string)ViewState["FeedUrl"];
else
return "http://www.peppedotnet.it/Blog/Rss.aspx";
}
set
{
ViewState["FeedUrl"] = value;
View.RaiseChangedEvent();
}
}
private FeedDataSourceView View
{
get
{
if (view == null)
view = new FeedDataSourceView(this, ViewName);
return view;
}
set { view = value; }
}
public FeedDataSource()
{
}
protected override DataSourceView GetView(string viewName)
{
if (String.IsNullOrEmpty(viewName) ||
(String.Compare(viewName, ViewName,
StringComparison.OrdinalIgnoreCase) == 0))
{
return View;
}
throw new ArgumentOutOfRangeException("viewName");
}
protected override System.Collections.ICollection GetViewNames()
{
return new string[] { ViewName };
}
}
}
Come potete vedere, il DataSource control FeedDataSource ha solamente la definizione delle proprietà e l'implementazione del metodo GetView, metodo che ritorna un'istanza della classe FeedDataSourceView (classe che eredita da DataSourceView e che incapsula la logica di gestione delle informazioni prelevate dalla fonte di dati).
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections;
using System.IO;
using System.Net;
using System.Xml;
namespace Peppe.Web.UI.WebControls
{
public class FeedDataSourceView : DataSourceView
{
private FeedDataSource control = null;
public FeedDataSourceView(FeedDataSource control, string viewName)
: base(control, viewName)
{
this.control = control;
}
protected override IEnumerable ExecuteSelect(DataSourceSelectArguments arguments)
{
RssItemCollection rssColl = null;
AtomCollection atomColl = null;
switch (this.control.FeedType)
{
case FeedType.Rss:
rssColl = GetRss(control.FeedUrl);
return rssColl;
case FeedType.Atom:
atomColl = GetAtom(control.FeedUrl);
return atomColl;
default:
return null;
}
}
internal RssItemCollection GetRss(string url)
{
//implementazione omessa, ma presente nei sorgenti da scaricare
}
internal AtomCollection GetAtom(string url)
{
//implementazione omessa, ma presente nei sorgenti da scaricare
}
internal void RaiseChangedEvent()
{
OnDataSourceViewChanged(EventArgs.Empty);
}
}
}
Il metodo principale, invece, della classe FeedDataSourceView è il metodo ExecuteSelect(), che appunto, esegue la SELECT sulle informazioni a disposizione. Questo metodo viene chiamato in automatico una volta che viene effettuato il DataBind da un secondo web control. Questo metodo vuole come tipo di ritorno una collezione di oggetti che implementi l'interfaccia IEnumerable, per questo ho inserito nel progetto d'esempio le classi RssItemCollection e AtomCollection che rappresentano rispettivamente collezioni di oggetti di tipo RssItem e di tipo Atom (oggetti anche questi custom, utili a salvare le informazioni lette dai file xml).
Ed ora, vediamone l’utilizzo di questo DataSource control.
<pep:FeedDataSource
ID="ds"
FeedUrl="http://www.peppedotnet.it/Blog/Rss.aspx"
FeedType="Rss"
runat="server" />
<asp:Repeater ID="rep" runat="server" DataSourceID="ds">
<ItemTemplate>
<a href='<%# Eval("Url") %>' title='<%# Eval("Title") %>'><%# Eval("Title") %></a><br />
</ItemTemplate>
</asp:Repeater>
La semplicità e la chiarezza di questo controllo dovrebbero saltarvi all'occhio. Non è presente alcuna riga di codice nel file di code-behind per effettuare il databinding, ma basta solamente legare i due controlli tramite la proprietà DataSourceID del Repeater ed il gioco è fatto.
Questo, come gia detto, è solo un esempio di base. Ad un progetto del genere possono essere aggiunti i parametri personalizzati, la gestione della cache e il supporto a design time, ma sono tutte implementazioni che lasciamo ai prossimi articoli.
Link utili
La classe DataSourceControl
La classe DataSourceView
|
|
|