Click here to Skip to main content
Click here to Skip to main content

Single (class) Instances in Multi-tenant Web Application

, 7 Apr 2010
Rate this:
Please Sign up or sign in to vote.
Need and implementation of single instance (class)

Introduction

In one of my recent works on multi-tenant web-based application, I required some class instances to be created only once. I was using multiple tenants created as ‘child’ under a single domain name. (ASP.NET/C# , DotNetNuke - DNN web application framework). Thus for such classes, I used the Singleton pattern but found that it was not solving my problem fully.

Background

Singleton pattern is used to ensure that exactly one object is created of a desired class. But in such an application (more than one tenant), it was common to all of them.

In the below diagram, the singleton instance is common to the single domain name/server.

E.g. http://www.example.com

I need a ‘single’ instance of my concrete class common to a virtual site whereas singleton instance is common to all the virtual sites. Thus here, the singleton class was not solving my problem. For better reference from now onwards, I'll use word ‘Single instance’ for such unique instances.

Thus for my work, I created a class that suits my need. It helps in creating such unique instances. Unlike singleton instance, these instances are saved in the requested state by developer.

This approach can help a developer to save such instance in any of the following storage/state:

  1. Session: Instance is stored in currently active session
  2. Cache: Instance is stored in Cache
  3. Database: If any custom schema/storage algorithm is designed (e.g. RDBMS)
  4. Custom: Any other user defined state (e.g. DBMS)

In currently attached sample class, all these storage functionalities have not been implemented as 3 and 4 options are specific to one application's design and database schema used.

For most frequently used classes, a more appropriate place will be Cache.

Instances Created (As Per My Mentioned Design)

The above diagram modified with Single instances when Cache is used for storage of various instances.

The above diagram modified with Single instances when Session is used for storage of various instances.

Session approach is not suggested as:

  1. Saving class instance in Session may unnecessarily reduce performance.
  2. If you are using third-party framework like: DNN then on user’s sign-out you have to ensure that they have abandoned user’s session.

Explanation

I assumed that I have a ‘SiteInfo’ class that stores some critical information about currently being used virtual site. Its instance must be unique for each virtual site. Since the code base used is the same for all, the singleton class will not solve this issue. Somehow these instances have to be separated. As I'm using DotNetNuke framework for developing such a web application, my example will utilize DNN (DotNetNuke) compliant code. But I will try to explain the logic with common words.

Projects used in Visual Studio:

First C# project has a class ‘SiteInfo’.

InstanceFactory’ is the project used to create single instances.

DNN' is the name of web application used.

InstanceFactory’ uses reflection along with double-check locking for creating various instances. For verifying logic used, I created a compiled module of DNN (named ‘Testing’) which actually provides the means of developing your controls/interface which will be finally accessible / visible to the end user through the virtual site.

Code as in Page_Load of used module in application

protected void Page_Load(object sender, System.EventArgs e)
        {
            try
            {
                // Getting single instance as saved in Cache
                SiteInfo info = AbstractInstance<SiteInfo>.GetInstance
                	(InstanceTypeState.Cache, PortalId);

                if (info != null && string.IsNullOrEmpty(info.PortalName))
                {
                    info.PortalName = PortalSettings.PortalName;
                }

                if (info != null)
                {
                    CacheValue.Text = info.PortalName;
                }

                // Getting single instance from Session
                SiteInfo siteInfo = AbstractInstance<SiteInfo>.GetInstance();

                if (siteInfo != null && string.IsNullOrEmpty(siteInfo.UsedByUser))
                {
                    siteInfo.UsedByUser = UserInfo.Username;
                }

                if (siteInfo != null)
                {
                    SessionValue.Text = siteInfo.UsedByUser;
                }

                // Using singleton-pattern class
                if (string.IsNullOrEmpty(TryClass.Instance.Name))
                {
                    // Current portal's name is displayed using singleton instance
                    TryClass.Instance.Name = PortalSettings.PortalName;
                }

                SingletonValue.Text = TryClass.Instance.Name;
            }
            catch (Exception exc)
            {
                //Module failed to load
                Exceptions.ProcessModuleLoadException(this, exc);
            }
        }

In case one is testing this approach on some other mean (not DNN), then use the above mentioned code in your first page_load.

Results (Output on Web Browser) to Verify Logic Used

A page in such a web site has three labels with the following captions:

  1. Label from Cache
  2. Label from Session
  3. Value from Singleton class

The first label is used to display the name of current portal (virtual site) used.
The second label is used to display the current user's name.
The third label is also used to display the name of the current portal (virtual site) used.

All the values are coming from various single instances of the same class 'SiteInfo' (above code snippet).

Following parameters/inputs are used for testing ->

1 Portal (virtual site) used-name: Videocon
User used: adminvideocon
URL used: http://localhost/dnn/videocon/Home.aspx

Result from web-browser

2 Portal (virtual site) used-name: Sony
User used: adminsony
URL used: http://localhost/dnn/sony/Home.aspx

Result from web-browser

The value after the first caption varies as per current portal’s (virtual site’s) name.
The value after the second caption varies as per current logged in user.
The value after the third caption is the same for all the cases which come from a singleton class.

Thus in the code snippet attached logic/call made ensured that the first label is utilizing a single instance as saved in Cache. Here I'm providing an input as ‘unique id’ which in my case is actually an identifier provided to various virtual sites. The second call is using Session for getting a single instance which is user specific. The third call is a traditional singleton call.

I've not displayed data using other states (RDBMS / DBMS) even though the provided file provides an option for them too as their implementation is more specific to an individual’s need in such a complex application. One can even modify Cache’s method used in the provided abstract class to completely skip Session based instance.

Advantages of Following this Structure

  1. It allows a single instances among multiple virtual application instances (not singleton).
  2. As per source code attached, it utilizes mainly cache which ensures fast data retrieval also one can decide how long an instance should reside (using expiration in cache).
  3. As stated in example (attached code snippet), a class can have multiple single instances like: SiteInfo class has two instances, one is saved in cache while other resides in active session. Both instances are unique and can be easily identified and called. This can be helpful in some complex requirements because of flexibility provided.
  4. Concrete class used in this example ‘SiteInfo’ has a private constructor (other code in it is only a public property) which ensures that its instance cannot be created by calling it directly.
  5. If one wants to ensure that no one should be able to create its (concrete class) separate instance even through reflection, then one option is to inherit the described abstract class (attached) and in its protected constructor ensure that no instance of calling concrete class exists else throw an exception. Existing instances can be checked as we will know in advance which state is actually used for saving this instance type (Session / Cache / DBMS etc.).

Some Limitations (Issues) Linked

  1. This design is different from the actual meaning of ‘singleton’. It is a customized way to achieve a completely different functionality as per the requirement.
  2. Using it, one cannot create a singleton instance. For it, one needs to create a separate class/logic. I recommend you to read the following article: http://www.codeproject.com/KB/architecture/GenericSingletonPattern.aspx by Martin Lapierre. It explains how to implement Singleton with generic/reflection approach.
  3. This logic is written keeping in mind only info / entity classes which are used to store some critical data and their objects do not perform any action. However there is no limitation in the code used. The only change will be in the kind of storage used for instances.

Points of Interest

This work helps me in better understanding of complex web applications development.

History

  • April 05, 2010: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

r verma
Software Developer
India India
No Biography provided

Comments and Discussions

 
QuestionDeveloping a Multitenant Application in Java Pinmembersangeetha_spss12-Oct-10 3:33 
AnswerRe: Developing a Multitenant Application in Java Pinmemberr verma12-Oct-10 16:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140721.1 | Last Updated 7 Apr 2010
Article Copyright 2010 by r verma
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid