From the Suggestion Box: Reusing object instances with ObjectDataSource
From the suggestion box Marc Brooks asks:
"More about the needed fixes for ObjectDataSource (e.g. allowing it to acquire the object instead of creating exnilo)."
In fact, the ObjectDataSource already supports this functionality through its ObjectCreating and ObjectDisposing events. In the attached ZIP file (download it from the bottom of this post) I have a sample web site that demonstrates a factory for business objects. Some details of the factory:
- The factory maintains a fixed-sized pool of business objects (the size is configurable).
- Initially no objects are created.
- Objects are created on demand, if they are needed.
- Objects are reused when available.
- Objects are returned to the pool by the consumer (the page developer does this).
Business object factory API:
namespace Eilon.Samples {
public static class BusinessObjectFactory {
public static BusinessObject GetBusinessObject();
public static void ReturnBusinessObject(object o);
}
}
The sample object in the demo has some calls to Thread.Sleep in it to help demonstrate expensive operations. Each business object instance takes two seconds to initialize, and each call to its Select method takes another two seconds. By making several rapid requests the demo shows that the object pool's maximum size of three objects is quickly exhausted. As mentioned earlier, we need to wire up the business object factory to the ObjectDataSource using some events:
protected void ProductsDataSource_ObjectCreating(object sender, ObjectDataSourceEventArgs e) {
e.ObjectInstance = BusinessObjectFactory.GetBusinessObject();
}
protected void ProductsDataSource_ObjectDisposing(object sender, ObjectDataSourceDisposingEventArgs e) {
BusinessObjectFactory.ReturnBusinessObject(e.ObjectInstance);
}
...
<asp:ObjectDataSource
ID="ProductsDataSource"
runat="server"
TypeName="Eilon.Samples.BusinessObject"
SelectMethod="GetProducts"
OnObjectCreating="ProductsDataSource_ObjectCreating"
OnObjectDisposing="ProductsDataSource_ObjectDisposing">
</asp:ObjectDataSource>
Running the demo:
- Unzip the attached application and either run the file-system Web site from Visual Studio or use IIS to create a virtual directory for it.
- Request the page from within the browser. You'll note at the top of the page the status reports something along the lines of:
Getting object from pool. @633053217271
Creating new object #0. @633053217271
Returning #0 to pool. @633053217341
In this case there are no objects in the pool, so a new one is created and then returned to the pool. - Hit refresh in your browser and you'll see this status:
Getting object from pool. @633053218295
Reusing object #0. @633053218295
Returning #0 to pool. @633053218345
This is almost identical to the previous status except that it is reusing object #0 instead of creating a new one. - Now for the fun stuff, pay attention closely: Open four instances of your browser in different processes. By this I mean that you should not open one instance of IE or Firefox and then just open new tabs or new windows from the same process. You need to actually have four separate iexplore.exe or firefox.exe processes running. This is critical because by default at least some browsers only allow two simultaneous connections to the same domain in a given process. By having separate processes you'll be able to make four requests to the same page in the same domain at the same time.
In each of the four browser windows hit the demo page - you have only about two seconds to do this! The status will be something like this:
Browser 1: Reusing the object from step #3.
Getting object from pool. @633053220563
Reusing object #0. @633053220563
Returning #0 to pool. @633053220613
Browser 2: Since object #0 is still in use by Browser 1, a new object needs to be created.
Getting object from pool. @633053220567
Creating new object #1. @633053220567
Returning #1 to pool. @633053220637
Browser 3: Since object #0 and #1 are both in use, another object needs to be created.
Getting object from pool. @633053220575
Creating new object #2. @633053220575
Returning #2 to pool. @633053220645
Browser 4: The entire object pool is in use since the max is 3 objects. We do a busy-wait loop until an object is available.
Getting object from pool. @633053220580
Pool is entirely in use, waiting... @633053220580
...
Pool is entirely in use, waiting... @633053220613
Reusing object #0. @633053220614
Returning #0 to pool. @633053220664
Feel free to reuse this code for the business object factory, but be aware that it suffers from serious starvation issues due to its busy-wait loop. Using a more dynamic system for maintaining the pool such as a dynamic size might be more appropriate for some systems. This code is just meant to demonstrate a lesser known feature of the ObjectDataSource.
- Eilon