Link to home
Start Free TrialLog in
Avatar of ppastor
ppastor

asked on

Should I use a Singleton or a cached object?

I am build ing an ASP.NET application and the pages and user controls interact with a library of custom business objects for getting data, etc...
In addition, I have designed things (so far) so that the business objects could be used by a winForms application if the client should decide to go down that path as well.
Finally, I am a big fan of declaring TraceSwitches in the application's config file (either web or app) because of the flexibility of being able to turn these switches on or off at runtime. The downside to these traceswitches is that you must instantiate a new TraceSwitch object when you want to determine the current switch setting. If your code uses a "reasonable" number of trace messages, it seems that instantiating a TraceSwitch object on every call could be an expensive proposition.

With that in mind, I have been considering options to minimize the number of TraceSwitch instantiations.

One thought was to create a "thread-safe" Singleton class in my business object library. This would statisfy my desire for something that could be called by the web app or the business tier, but I am concerned about performance. My understanding is that all requests within the aspnet_wp would be funneled through this instance, and that would probably be very detrimental.

Another option is to create an instance of the TraceSwitch object in the HttpCache. This should perform much better than the Singleton, and all of the UserControls and current aspx page could access this instance. The downside here is that I still do not have a solution for the business tier (unless I just assume that there is an HttpContext to hook into...but that breaks my hopes of porting to WinForms).

A solution to this is greatly appreciated!

Thank you,

Phil
Avatar of Jesse Houwing
Jesse Houwing
Flag of Netherlands image

I'd create a singleton by adding the object to the HttpContext.Application collection. This collection is unique for the whole application.

If you don't need anything else but the true/false for the enabled property, then I suggest adding only this boolean to save space and to prevent possible locking problems.

You can use the Application_Start in the Global.asax to setup the variable once per application startup to save even more performance.
Avatar of ppastor
ppastor

ASKER

ToAom,

Thank you for your reponse.

I was trying to keep things simple in my original post, but when implementing tracing I need to do more than just determining whether or not it is enabled. My code would want to know at what level the tracing is enabled (ie. Verbose, Warning, Error, etc...). Then, if the switch setting matches (or is more general) than the required switch level, then it can write the message to the log.

I understand that I can instantiate an object in the Application_Start, but what of the performance concerns of funneling thousands of requests through a single instance?

Phil
HttpContext will spoil u r functionality of porting the Business Layer to WinForms.

If you have a Business Manager Class or something of that sort then there is another possible solution.
The BM class can have a initilize method, this method will accept a TraceSwitch object and the tracing will happen using this object.

In the web scenario a new session will mean a new TraceSwitch object, where as in the WinForms a new client will mean a new TraceSwitch object.

You can always access the current HttpContext from any layer in the application by calling HttpContext.Current. For your windows forms solution a static variable is probably the best choice. So it will result in a function like the following to make it work in both worlds:

The current context is null if you're not in an ASP.net application. So if you create a class with a static property for the TraceSwitch object like so:

public class TraceSwitchSingleton
{
      private TraceSwitchSingleton(){}
      static TraceSwitchSingleton()
      {
            if (System.Web.HttpContext.Current == null)
            {
                  // Or move these 5 lines to the application start method.
                  System.Web.HttpContext.Current.Application.Lock();
                  if (!System.Web.HttpContext.Current.Items.Contains("TraceSwitch__Instance"))
                  {
                        System.Web.HttpContext.Current.Application.Add("TraceSwitch__Instance", new TraceSwicth());
                  }
                  System.Web.HttpContext.Current.Application.Unlock();
            }
            else
            {
                  _instance = new TraceSwicth();
            }
      }

      private static TraceSwitch _instance = null;

      public static TraceSwitch Instance
      {
            get
            {
                  if (System.Web.HttpContext.Current == null)
                  {
                        if (System.Web.HttpContext.Current.Items.Contains("TraceSwitch__Instance"))
                        {
                              return System.Web.HttpContext.Current.Application["TraceSwitch__Instance"];
                        }
                  }
                  else
                  {
                        return _instance;
                  }
            }
      }
}

This class should be usable in both types of applications. Just make sure lock the instance if you're doing more than reading properties.
There will be no performance issue if you're using a single object as long as you're just reading it's properties. It would become more of a problem if you're altering it's properties a lot, but from your question that isn't likely. It will proably even improve performace because you won't have to set up a TraceSwicth object for every call, you'll save the memory and you'll save CPU because the Garbage collector won't have to cleanup all the objects.

We use a very similar object for our Database Transaction so that multiple data access classes can participate in the same transaction without having to pass the instance to every method. It works brilliantly in both forms and web.
ASKER CERTIFIED SOLUTION
Avatar of Jesse Houwing
Jesse Houwing
Flag of Netherlands image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
if you are using the TraceSwitch Object to pass the information about the trace state, then what Toaom says will work perfectly, but if your TraceSwitch object also exposes logging function then i think u need more then one object.

 
This code will always create a new object of TraceSwitch in WinForms

 if (System.Web.HttpContext.Current != null)
            {
                  // Or move these 5 lines to the application start method.
                  System.Web.HttpContext.Current.Application.Lock();
                  if (!System.Web.HttpContext.Current.Items.Contains("TraceSwitch__Instance"))
                  {
                        System.Web.HttpContext.Current.Application.Add("TraceSwitch__Instance", new TraceSwicth());
                  }
                  System.Web.HttpContext.Current.Application.Unlock();
            }
            else
            {
                  _instance = new TraceSwicth();
            }


never mind my prevois comments
Avatar of ppastor

ASKER

jkunal,

Yes, my intent was to also handle the actual writing of the trace message through this instance. But then the issue becomes regardless of how many requests I can handle...they all have to wait in line to get access to the log (assuming that the object determined it was cleared to write the message depending on level).

And, if I am using some type of BusinessManager class, I have been having difficulty getting my head around how this would work. When you mention an "Initialize" method, do you mean a "constructor"? If so, then that requires a "global" instance of the object that can be referenced. Does it not? And, if I call a static method on the class, then it can not maintain it's own instance of the TraceSwitch object. Correct?
I made sure that happened in the static constructor.
The block of code I provided will make sure there is an instance you can work with at all times. That's what the static constructor is for.

static TraceSwitchSingleton()

The write will probably be faster because the TraceSwitch class can manage it's own lock and won't have to rely on the OS to signal when the file becomes available.

If in doubt, download a profiles (like the DevPartner .Net profiler Community Edition (free)) and try both options to see which one is faster.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of ppastor

ASKER


I thank you both for your assistance! If I knew how to give you both the 500 I would!