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:

  1. 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.
  2. 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.
  3. 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.
  4. 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

1 Comment

  • Well let's call that "oops" :)

    The reason for what you're describing is an unfortunate consequence of the design we have for data sources and data bound controls. Since ASP.NET pages are generally stateless with respect to the server, all live objects go away after the page is unloaded. The data source relies entirely on the data bound control to give it the old/new values that it needs.

    On the other hand, once nice consequence of the design is that the requirements on the business objects are quite few. We require no support for any type of persistence or serialization. The only requirements are a pattern for the object model regarding the signatures of the constructor(s) and availability of property getters and setters on the data object.

    I am interested to hear any ideas you have on how your ideal data source might work, though. Where should the data objects be persisted? Any other aspects that need to be handled here?

    - Eilon

Comments have been disabled for this content.