Cache In Using the ObjectDataSource Control
Object Instantiation and Data Caching
October 30, 2009
CoreCoder
LANGUAGES: C#
ASP.NETVERSIONS: 2.0
Cache In Using the ObjectDataSource Control
Object Instantiation and Data Caching
By Dino Esposito
One of the hot new features of ASP.NET 2.0, data sourcecontrols are far from being the panacea of all data access pains. First andforemost, data source controls are not the only way to bring data into anapplication. A data source control is just one of many controls in the ASP.NETtoolbox, and should be used when it proves to be the right tool for the job youhave to do.
A data source control exists as a counterpart to adata-bound control, so that the process of binding can be run moreintelligently and with less glue code. My personal philosophy is that youshould stop using data source controls as you start facing difficulties. Eithermake it easy or use nothing. As with many emphatic sentences, this one also hassome truth to it but it should not be taken literally, either. Basically,data source controls are complex and sophisticated mechanisms; as such, theyare delicate at times, and breaking them from code might be easier than youexpect.
In this article, I ll bring the ObjectDataSource control tothe forefront and delve into some of its little-known features regarding objectinstantiation and data caching.
Quick Refresher
A data source control is mostly a wrapper around adata-source-view class. In general, a data source control represents one ormore named views of data and each view manages a collection of data. Allbuilt-in data source objects, though, implement only one default view. However,this is the exception. A data source view manages its data through SQL-likeoperations such as SELECT, INSERT, DELETE, and UPDATE. Optionally, a datasource view can implement a number of extra capabilities, such as sorting andpaging. In ASP.NET 2.0, data source controls come in two flavors: tabular andhierarchical. The table in Figure 1 details all default data source controls.
Class | Description |
---|---|
AccessDataSource | Connects to an Access database and uses the Jet 4.0 OLE DB provider to operate. |
ObjectDataSource | Connects to a custom .NET business object that returns data. |
SiteMapDataSource | Hierarchical control; connects to any provider that supplies site map information. |
SqlDataSource | Connects to an ADO.NET data provider that returns relational data. You specify the name of the provider and the connection string through properties. |
XmlDataSource | Hierarchical control; connects to XML data with or without schema information. |
Figure 1: Details ofthe default data source controls.
It is essential to know that SqlDataSource is not a datasource control for SQL Server data. Instead, it can manage any relational dataobtained through a variety of ADO.NET data providers, including those for OLEDB and ODBC data sources.
ASP.NET 2.0 data-bound controls have been refactored tosupport binding through data source controls. In particular, all standarddata-bound controls support binding through data source objects; only newdata-bound controls, such as GridView and DetailsView, though, support two-waydata binding via data source objects. To exemplify, you can populate a DataGridor a Repeater using a data source control. You can t edit in-place the contentsof a grid row, though. For this to happen, you must upgrade the DataGrid to theGridView control.
ObjectDataSource and Your BLL/DAL
The key difference between the two controls is in thelevel of abstraction they support and require. There s virtually no dataabstraction with SqlDataSource. You must indicate connection string and commandtext in ASP.NET pages. This might be acceptable for short-lived,quick-and-dirty pages, but it is hard to push for an enterprise-levelapplication with its own business logic (BLL) and data access layer (DAL).ObjectDataSource encapsulates data access details and security in a set ofobjects most likely your existing BLL/DAL.
Objects you plan to use with ObjectDataSource need to meeta number of requirements (so you can t plug any objects in). In particular, theobject must expose a default parameterless constructor, be stateless, and havemethods that easily map to select, update, insert, and delete semantics. Inaddition, the object must perform updates one item at a time as batch updatescenarios are not explicitly supported. However, it is essential to note thatsuch a requirement applies exclusively at the API level. In other words, yourobject must have an Update method that doesn t require any further action topersist changes. This fact alone doesn t prevent you from using batch updatepolicies in your DAL. If your DAL does use batch update policies, then it is upto you to trigger the extra tasks that will actually move updated records frommemory to disk. This can be done either adding some UI (for example, a Save toDB button) or scheduling a background service that does that periodically.
The bottom line is that managed objects that work wellwith ObjectDataSource are designed with this data source class in mind.
It is not uncommon and, indeed, recommended that you designyour BLL/DAL independent from the ObjectDataSource control. When you have amiddle-tier that completely satisfies your requirements, you start reasoningabout ways to connect it to an ObjectDataSource. In doing so, you typicallyface two issues: adapting the API and deploying the BLL/DAL.
Because ObjectDataSource has expectations on the API ofthe bound class, it might happen that objects in your BLL/DAL do not complywith the ObjectDataSource rules. For example, mapping CRUD operations onObjectDataSource to methods in the class might not be immediate. The patternAdapter comes to the rescue. This pattern helps when class A and class B mustcommunicate, but lack matching interfaces. In this case, you create a class Cthat wraps class A into an interface that class B understands.
The same pattern is helpful when you deploy yourmiddle-tier and the ASP.NET application on separate servers. ObjectDataSourcecan t directly call into a remote object. Once again, you wrap the bound objectin a local proxy object that uses .NET Remoting, WCF, Web services, or whateverelse to connect to the BLL/DAL. Figure 2 illustrates this scenario.
Figure 2: Using ObjectDataSourcewith a remote/firewalled object.
Object Creation
The bound BLL/DAL class is instantiated each and everytime the ObjectDataSource control is created; that is, for each page request.For each page request, the BLL/DAL class goes through the standard cycle:create, use, dispose. As you can see, no state is automatically maintainedexcept any state the class itself saves internally to persistent media, such asfiles or databases. If the BLL/DAL class has static methods, some state can bemaintained through static members. In this case, though, be prepared to handlepossible concurrent access to these members.
The ObjectDataSource control first looks for the defaultconstructor of the class. If such a parameterless constructor can be found,then the object is created, consumed, and disposed of. Otherwise,ObjectDataSource fires a server-side event (ObjectCreating):
private void OnObjectCreating(object sender,
ObjectDataSourceEventArgse)
{
// i.e. Need to use anon-default ctor
CustomerManager cm;
cm = newCustomerManager( ... );
// Pass the object on
e.ObjectInstance = cm;
}
By handling this event, the page code can work around acouple of relevant issues. First, the event handler can use any non-defaultconstructor the BLL/DAL may have. Second, you can retrieve a valid classinstance from an internal cache; for example, the ASP.NET Cache object. In thisway, you create just one instance of the BLL/DAL object and reuse it acrossrequests. Just the repeated creation and disposal of a class instance, in fact,might affect the overall performance of the system.
The ObjectCreating event is fired to give the page achance to manually create the instance. When the event returns,ObjectDataSource checks the ObjectInstance property of the event argumentclass. If the property is not null, ObjectDataSource will use the instancereturned by the event instead of creating an instance on its own. TheObjectCreated event is also fired later to let the page author access anypublic members of the object and perform additional initialization.
It is worth noting that the behavior of ObjectDataSourceis slightly different if static methods are used. Actually, one of the firsttasks that ObjectDataSource performs after initialization is discoveringinformation about the method to invoke. Static methods are invoked immediately;otherwise, an instance of the BLL/DAL object must be created first, either viathe default constructor or the ObjectCreating event. In any case, as it isfairly easy to guess, methods and constructors are invoked via reflection. Whendone, ObjectDataSource signals it is going to free up the BLL/DAL object. Itdoes that through the ObjectDisposing event. If you re going to reuse thatinstance, simply cancel the dispose operation, as shown in Figure 3.
private void OnObjectCreating(
object sender,ObjectDataSourceEventArgs e)
{
// Check if an instancealready exists in the Cache
CustomerManager manager =Cache["CustomerManager"]
as CustomerManager;
if (null == manager)
manager = newCustomerManager();
e.ObjectInstance =manager;
}
private void OnObjectDisposing(
object sender,ObjectDataSourceDisposingEventArgs e)
{
// Get the businessobject and check if it
// exists already in theCache
CustomerManager manager =e.ObjectInstance
as CustomerManager;
CustomerManager temp =Cache["CustomerManager"]
as CustomerManager;
if (null == temp)
Cache.Insert("CustomerManager", manager);
// Cancel, so that theobject won't be disposed
// if it implementsIDisposable
e.Cancel = true;
}
Figure 3: CachingBLL/DAL Objects.
Caching Data
As mentioned, ObjectDataSource doesn t automatically cachethe BLL/DAL object across requests, but it can optionally cache the results ofthe Select method the data to return to data-bound controls. For this tohappen, you only have to set up a few properties: EnableCaching, CacheDuration,and CacheExpirationPolicy. You don t need to modify your business and datalayers to enjoy caching, because caching takes place one level up (at theObjectDataSource gate). Basically, when the data-bound control invokes theSelect method, ObjectDataSource first checks if there s any valid data in thecache. If not, it serves the request by invoking the back-end object.Otherwise, the request is served with existing data and your BLL is happilybypassed.
When you set the EnableCaching property to true (thedefault is false), the data returned by the Select method are stored in theASP.NET Cache object and reused over and over again until it expires.CacheDuration and CacheExpirationPolicy properties let you control theexpiration of data. In particular, CacheDuration sets for how long the resultsof the Select method should stay cached. You assign CacheDuration a time (inseconds). CacheExpirationPolicy, on the other hand, defines the expirationpolicy with respect to the duration. If set to Absolute, then the data in thecache becomes obsolete after the specified period. If set to Sliding, instead,each successful access to the cached data automatically renews the cachingperiod. For example, in case of sliding expiration and a duration of 30seconds, data gets stale if not accessed for more than 30 seconds. In case ofabsolute expiration, instead, data gets stale 30 seconds after storage, nomatter how many times it has been read meanwhile.
ObjectDataSource creates an entry in the ASP.NET Cache tostore data. A unique entry is created for every combination of CacheDuration,CacheExpirationPolicy, TypeName, SelectMethod, and SelectParameters values.This means that multiple ObjectDataSource controls in the same application willuse the same data if they connect to the same BLL/DAL object and call the samemethod with the same parameter with the same caching settings.
An application that uses cached data returns datagenerally faster than an application that has to hit the database each time.However, with caching enabled there s no guarantee that data you serve is up todate. The first consideration to make is, are you really sure you can t affordcaching data for just a few seconds? If you set up a cache duration of 5 seconds,it means that users will see data with a maximum delay of 5 seconds. Are you(and your users) really sure this violates requirements? How many requests canyou serve much faster in, well, 5 seconds of server time?
The second consideration relates to the meaning of thedata. Imagine a scenario where you cache relatively static data for a long time;for example, customer information or product descriptions. No matter for howlong the data is fixed, you might want to see changes show up soon. In this case,you might consider adding a dependency mechanism that invalidates cached datawhen real data in the back-end data store changes.
The CacheDependencyKey property indicates a user-definedcache entry that is linked to the ObjectDataSource entry that contains cacheddata. By programmatically changing the value in the user-defined key, youinvalidate any cached data so that the next request will be served going backto the database and return fresh data:
// Invalidate programmatically any cached data and refresh
Cache[ObjectDataSource1.CacheKeyDependency] = new object();
GridView1.DataBind();
If cached data come from a database, you can also set up adirect dependency between cached data and a database table. TheSqlCacheDependency property of the ObjectDataSource control binds the cacheddata to changes in the specified table of the specified database. You indicatethe database using the DatabaseEntry:Table format.
Finally, keep in mind that ObjectDataSource allows you tocache any types of data, including DataTable and custom collections. However,you should not cache objects that retain resources or state that cannot beshared to service multiple requests. Want an example? You should never, ever,cache an open SqlDataReader object.
Conclusion
In ASP.NET 2.0, all data-bound controls support twobinding mechanisms. One is the classic binding also available in ASP.NET 1.xand done through enumerable data source objects. The second mechanism relies ondata source controls. Data source controls are regular server controls with nouser interface that intelligently cooperate with the data-bound control tryingto anticipate the next user s request. ObjectDataSource is the most interestingof the data source controls because it can bridge your presentation layer tothe BLL/DAL, even remotely. The ObjectDataSource control takes advantage ofexisting tiers and, overall, promotes a domain-based design over a purelytiered design. In this article, I focused on some programming aspects ofObjectDataSource. I ll delve into more in future columns. Stay tuned.
Dino Esposito is aSolid Quality Learning mentor and the author of IntroducingASP.NET 2.0 AJAX Extensions and ProgrammingMicrosoft ASP.NET 2.0-Core Reference, both from Microsoft Press. Basedin Italy, Dinois a frequent speaker at industry events worldwide. Join the blog at http://weblogs.asp.net/despos.
About the Author
You May Also Like