views:

101

answers:

3

I just started migrating my web application to fully use Windsor IOC. Here is a little problem I am encountering;

I have couple of static classes which I used to store some application level global values

EG (Simplified version of the class):

public static class SiteInfo
{
        public static Language Language = (Language)byte.Parse(SiteInfo.Val("language"));
        public static string Code = Site.Code;
        public static string Name = Site.Name;

        public static SiteCachedData CachedData { get; set; }
        public static Site Site { get; set; }

       public static void Init()
       {
          //Get site info from DB here
          //I need to inject _SiteRepository here but I can't 
          //since I don't have access to the constructor
       }
}

I am new to IOC and I understand static classes are advised to be prevented. What is the good practice to handle this situation? I am thinking of converting this to a singleton but I am not sure if that is my best bet.

A: 

You can register an single instanec of a class in your container, so it behaves like a singleton. The container gives you the same instance every time.

James L
+1  A: 

This is one of the reasons why I like to avoid static classes --they are hard to inject or invert control. They usually have to know intimate details of several low level classes. Since they are static classes you can leave them because they are already available to all of the other classes and don't require injection.

One trick that I've done is to create a second class that delegates into the static class. You can then put an interface onto the new class and get into an IoC framework easier.

public static class StaticClass   
{  
    public static object Method()   
}

public class NonstaticClass : INewInterface  
{  
    public object Method()  
    {  
        return StaticClass.Method();  
    }  
}

The good part of this refactor is that you can go method by method and then determine new objects and interfaces as you go. Eventually you may be able to get rid of the original static class. You would also register the new classes as singleton instances so that only one instance exists at a time.

Jerod Houghtelling
+1  A: 

In the context of an IoC container, it's a bit ambiguous to say 'convert it to a singleton'. If you mean the singleton design pattern, you probably shouldn't do it that way, as there are better alternatives in the IoC world.

IoC containers perform two main roles: to resolve dependencies between components, and to manage the lifetime of components. A container manages the lifetime of its components by deciding when to create and destroy component instances.

For example, when you call container.Resolve<SiteInfo>(), the container has to decide whether to re-use an existing SiteInfo instance or create a new one. How does the container decide? Well, when you register SiteInfo with the container, you can tell the container how you would like it to behave. If you register it as a Singleton, the container will only create a SiteInfo instance on the first call to container.Resolve<SiteInfo>(); on subsequent calls, it re-uses the existing SiteInfo instance.

The advantage of this technique over the singleton pattern is flexibility. If you use the design pattern, your SiteInfo class will forever be a singleton (unless you refactor). By using the container to manage the lifetime, you can change your mind later and just change the container registration code. Consumers of the component don't need to (and shouldn't) care whether the container provides them with a new instance or re-uses an existing one - they just call container.Resolve().

I'm not familiar with Windsor (I use Autofac), but it looks like you have two ways of registering a component as a singleton (I'm sure someone will correct me if this is wrong):

container.AddComponentLifeStyle<SiteInfo>(LifestyleType.Singleton)

or,

container.Register( Component.For<SiteInfo>()
                    .LifeStyle.Singleton );

However, a word of warning. In your example, your SiteInfo class has a dependency on the _SiteRepository class. You will therefore also need to register a _SiteRepository instance as a singleton in the container, so that it is available when the container resolves the SiteInfo. This _SiteRepository instance will remain in memory for the lifetime of the container, i.e. for the lifetime of the Web application, because it's a singleton. If the repository keeps a DB connection open, therefore, that connection will remain open for the same lifetime.

For this sort of reason, an alternative lifestyle is per-web-request - in other words, the container will create a new instance of your SiteInfo class once per web request. The per-web-request lifestyle is discussed in another question.

RichTea