From f69b3e9b974ce8c39eb4c80d62a46d8fadcb1f16 Mon Sep 17 00:00:00 2001 From: "Morten@Thinkpad-X220.ab-nat1.dk" Date: Tue, 9 Oct 2012 16:07:19 -0200 Subject: [PATCH] Refactoring singleton implementation for DatabaseFactory and Repository Cache Providers as per recommendations from http://csharpindepth.com/articles/general/singleton.aspx Adding unit test for DatabaseFactory. --- .../Caching/InMemoryCacheProvider.cs | 18 ++++--------- .../Persistence/Caching/NullCacheProvider.cs | 19 ++++---------- .../Caching/RuntimeCacheProvider.cs | 20 +++++---------- .../Persistence/DatabaseFactory.cs | 25 +++++-------------- .../Repositories/PetaPocoRepositoryBase.cs | 2 +- .../Persistence/DatabaseFactoryTests.cs | 18 +++++++++++++ src/Umbraco.Tests/Umbraco.Tests.csproj | 1 + 7 files changed, 42 insertions(+), 61 deletions(-) create mode 100644 src/Umbraco.Tests/Persistence/DatabaseFactoryTests.cs diff --git a/src/Umbraco.Core/Persistence/Caching/InMemoryCacheProvider.cs b/src/Umbraco.Core/Persistence/Caching/InMemoryCacheProvider.cs index b6f763fb36..b474ebf62c 100644 --- a/src/Umbraco.Core/Persistence/Caching/InMemoryCacheProvider.cs +++ b/src/Umbraco.Core/Persistence/Caching/InMemoryCacheProvider.cs @@ -13,23 +13,15 @@ namespace Umbraco.Core.Persistence.Caching internal class InMemoryCacheProvider : IRepositoryCacheProvider { #region Singleton - private static volatile InMemoryCacheProvider _instance; - private static readonly ReaderWriterLockSlim Lock = new ReaderWriterLockSlim(); - private InMemoryCacheProvider() { } + private static readonly Lazy lazy = new Lazy(() => new InMemoryCacheProvider()); - public static InMemoryCacheProvider Current + public static InMemoryCacheProvider Current { get { return lazy.Value; } } + + private InMemoryCacheProvider() { - get - { - using (new WriteLock(Lock)) - { - if (_instance == null) _instance = new InMemoryCacheProvider(); - } - - return _instance; - } } + #endregion private readonly ConcurrentDictionary _cache = new ConcurrentDictionary(); diff --git a/src/Umbraco.Core/Persistence/Caching/NullCacheProvider.cs b/src/Umbraco.Core/Persistence/Caching/NullCacheProvider.cs index ad0baae235..fe196fa477 100644 --- a/src/Umbraco.Core/Persistence/Caching/NullCacheProvider.cs +++ b/src/Umbraco.Core/Persistence/Caching/NullCacheProvider.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Threading; using Umbraco.Core.Models.EntityBase; namespace Umbraco.Core.Persistence.Caching @@ -9,23 +8,15 @@ namespace Umbraco.Core.Persistence.Caching internal class NullCacheProvider : IRepositoryCacheProvider { #region Singleton - private static volatile NullCacheProvider _instance; - private static readonly ReaderWriterLockSlim Lock = new ReaderWriterLockSlim(); - private NullCacheProvider() { } + private static readonly Lazy lazy = new Lazy(() => new NullCacheProvider()); - public static NullCacheProvider Current + public static NullCacheProvider Current { get { return lazy.Value; } } + + private NullCacheProvider() { - get - { - using (new WriteLock(Lock)) - { - if (_instance == null) _instance = new NullCacheProvider(); - } - - return _instance; - } } + #endregion #region Implementation of IRepositoryCacheProvider diff --git a/src/Umbraco.Core/Persistence/Caching/RuntimeCacheProvider.cs b/src/Umbraco.Core/Persistence/Caching/RuntimeCacheProvider.cs index 35a735953d..21762f4cd4 100644 --- a/src/Umbraco.Core/Persistence/Caching/RuntimeCacheProvider.cs +++ b/src/Umbraco.Core/Persistence/Caching/RuntimeCacheProvider.cs @@ -13,26 +13,18 @@ namespace Umbraco.Core.Persistence.Caching internal sealed class RuntimeCacheProvider : IRepositoryCacheProvider { #region Singleton - private static volatile RuntimeCacheProvider _instance; - private static readonly ReaderWriterLockSlim Lock = new ReaderWriterLockSlim(); - private RuntimeCacheProvider() { } + private static readonly Lazy lazy = new Lazy(() => new RuntimeCacheProvider()); - public static RuntimeCacheProvider Current + public static RuntimeCacheProvider Current { get { return lazy.Value; } } + + private RuntimeCacheProvider() { - get - { - using (new WriteLock(Lock)) - { - if (_instance == null) _instance = new RuntimeCacheProvider(); - } - - return _instance; - } } + #endregion - private ObjectCache _memoryCache = new MemoryCache("in-memory"); + private readonly ObjectCache _memoryCache = new MemoryCache("in-memory"); private ConcurrentDictionary _keyTracker = new ConcurrentDictionary(); public IEntity GetById(Type type, Guid id) diff --git a/src/Umbraco.Core/Persistence/DatabaseFactory.cs b/src/Umbraco.Core/Persistence/DatabaseFactory.cs index 422896288d..6ce5bd6ac4 100644 --- a/src/Umbraco.Core/Persistence/DatabaseFactory.cs +++ b/src/Umbraco.Core/Persistence/DatabaseFactory.cs @@ -1,4 +1,5 @@ -using System.Threading; +using System; +using System.Threading; using Umbraco.Core.Configuration; namespace Umbraco.Core.Persistence @@ -11,27 +12,13 @@ namespace Umbraco.Core.Persistence { #region Singleton - private static Database _database; - private static volatile DatabaseFactory _instance; - private static readonly ReaderWriterLockSlim Lock = new ReaderWriterLockSlim(); + private static readonly Database _database = new Database(GlobalSettings.DbDsn); + private static readonly Lazy lazy = new Lazy(() => new DatabaseFactory()); - private DatabaseFactory() { } + public static DatabaseFactory Current { get { return lazy.Value; } } - public static DatabaseFactory Current + private DatabaseFactory() { - get - { - using (new WriteLock(Lock)) - { - if (_instance == null) - { - _instance = new DatabaseFactory(); - _database = new Database(GlobalSettings.DbDsn); - } - } - - return _instance; - } } #endregion diff --git a/src/Umbraco.Core/Persistence/Repositories/PetaPocoRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/PetaPocoRepositoryBase.cs index f6e47955d3..1d8f21605e 100644 --- a/src/Umbraco.Core/Persistence/Repositories/PetaPocoRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/PetaPocoRepositoryBase.cs @@ -15,7 +15,7 @@ namespace Umbraco.Core.Persistence.Repositories internal abstract class PetaPocoRepositoryBase : RepositoryBase where TEntity : IAggregateRoot { - private Database _database; + private readonly Database _database; protected PetaPocoRepositoryBase(IUnitOfWork work) : base(work) { diff --git a/src/Umbraco.Tests/Persistence/DatabaseFactoryTests.cs b/src/Umbraco.Tests/Persistence/DatabaseFactoryTests.cs new file mode 100644 index 0000000000..4a3337f1b2 --- /dev/null +++ b/src/Umbraco.Tests/Persistence/DatabaseFactoryTests.cs @@ -0,0 +1,18 @@ +using NUnit.Framework; +using Umbraco.Core.Persistence; + +namespace Umbraco.Tests.Persistence +{ + [TestFixture] + public class DatabaseFactoryTests + { + [Test] + public void Can_Verify_Single_Database_Instance() + { + var db1 = DatabaseFactory.Current.Database; + var db2 = DatabaseFactory.Current.Database; + + Assert.AreSame(db1, db2); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 10daacb5c4..befc241252 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -60,6 +60,7 @@ +