Thread safe .NET wurfl API (hopefully)

by Mikael Henriksson 29. April 2009 11:32

First of all I’d like to thank Luca Passani for all his great work with wurfl. He’s done a good job. The database is updated at least once a month and the community I suppose has done a good job with the different API’s. I can however not use the .NET API’s. They are not thread safe and I thought I’d share with you how I improved the old .NET API.

I started of with renaming pretty much everything since the names did not talk to me. We can call the in-memory wurfldatabase the WurflHolder and the class to navigate the holder is called WurflNavigator. The implementation details was changed a bit as well since it did not give me the correct results but that is a different blog post. Why did I make it a Singleton class you ask? Well I tried with a static class first but it caused issues all over the planet. I had people getting detected with a completely wrong mobile phone. Also the logs was totally not right. It basically cause the whole application to go wrong. I though maybe this is a good place for the Singleton pattern and I was right. I am not sure my Singleton implementation is completely thread safe but it is sufficient for now.

Let’s start with the Singleton instance:

public class Singleton<T> where T : class, new()
{
    protected Singleton()
    {

    }

    public static T Instance
    {
        get { return SingletonCreator<T>.CreatorInstance; }
    }

    private sealed class SingletonCreator<S> where S : class, new()
    {
        private static readonly S instance = new S();

        public static S CreatorInstance
        {
            get { return instance; }
        }
    }
}

I think the code speaks for itself. Basically if it’s not created I create it at runtime. The reason for making it generic is that I actually use it for two more classes. Then the API needs a couple of modifications, first in Global.asax we need to load the xml document:

Singleton<WurflHolder>.Instance.Load(HostingEnvironment.MapPath("/wurfl.xml"));

Then the default constructor for the Navigator needs to be changed to something like:

public WurlfNavigator()
{
    try
    {
        _wurflFileNotLoaded = Singleton<WurflHolder>.Instance.WurflFileNotLoaded;
        if (!Singleton<WurflHolder>.Instance.IsLoaded)
        {
            ThrowException(_wurflFileNotLoaded + ". Be sure that the creation of _wurfl have ran OK",
                           "prepareNavigatorModel");
        }
        _userAgentAndId = Singleton<WurflHolder>.Instance.UserAgentAndId;
        _idAndFallback = Singleton<WurflHolder>.Instance.IdAndFallback;
        _idAndCapabilities = Singleton<WurflHolder>.Instance.IdAndCapabilities;
        _capabilityNames = Singleton<WurflHolder>.Instance.CapabilityNames;
    }
    catch (Exception ex)
    {
        ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
        log.Error("WurlfNavigator", ex.InnerException);
    }
}

This totally stops all randomness in the entire website. maybe not the best thing to keep it in memory but hey, it’s better than total unreliability!

Tags: ,

C# | wurfl

blog comments powered by Disqus