diff --git a/src/Umbraco.Core/CoreBootManager.cs b/src/Umbraco.Core/CoreBootManager.cs
index b4122cbd8e..0ac6d18cd7 100644
--- a/src/Umbraco.Core/CoreBootManager.cs
+++ b/src/Umbraco.Core/CoreBootManager.cs
@@ -4,6 +4,7 @@ using System.Linq;
using System.Text;
using Umbraco.Core.Logging;
using Umbraco.Core.ObjectResolution;
+using Umbraco.Core.Persistence;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Core
@@ -96,6 +97,9 @@ namespace Umbraco.Core
///
protected virtual void InitializeResolvers()
{
+ RepositoryInstanceResolver.Current = new RepositoryInstanceResolver(
+ new RepositoryInstanceFactory());
+
CacheRefreshersResolver.Current = new CacheRefreshersResolver(
PluginManager.Current.ResolveCacheRefreshers());
diff --git a/src/Umbraco.Core/Persistence/Mappers/BaseMapper.cs b/src/Umbraco.Core/Persistence/Mappers/BaseMapper.cs
index fda1b4d7f1..86d5e026d8 100644
--- a/src/Umbraco.Core/Persistence/Mappers/BaseMapper.cs
+++ b/src/Umbraco.Core/Persistence/Mappers/BaseMapper.cs
@@ -5,7 +5,7 @@ using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Mappers
{
- public abstract class BaseMapper
+ internal abstract class BaseMapper
{
internal abstract void BuildMap();
diff --git a/src/Umbraco.Core/Persistence/Mappers/DictionaryTranslationMapper.cs b/src/Umbraco.Core/Persistence/Mappers/DictionaryTranslationMapper.cs
index fe8e1a3c83..7b0409c3b3 100644
--- a/src/Umbraco.Core/Persistence/Mappers/DictionaryTranslationMapper.cs
+++ b/src/Umbraco.Core/Persistence/Mappers/DictionaryTranslationMapper.cs
@@ -10,7 +10,7 @@ namespace Umbraco.Core.Persistence.Mappers
/// Represents a to DTO mapper used to translate the properties of the public api
/// implementation to that of the database's DTO as sql: [tableName].[columnName].
///
- public class DictionaryTranslationMapper : BaseMapper
+ internal class DictionaryTranslationMapper : BaseMapper
{
private static readonly ConcurrentDictionary PropertyInfoCache = new ConcurrentDictionary();
diff --git a/src/Umbraco.Core/Persistence/RepositoryInstanceFactory.cs b/src/Umbraco.Core/Persistence/RepositoryInstanceFactory.cs
new file mode 100644
index 0000000000..6f8212bc4b
--- /dev/null
+++ b/src/Umbraco.Core/Persistence/RepositoryInstanceFactory.cs
@@ -0,0 +1,140 @@
+using Umbraco.Core.Persistence.Caching;
+using Umbraco.Core.Persistence.Repositories;
+using Umbraco.Core.Persistence.UnitOfWork;
+
+namespace Umbraco.Core.Persistence
+{
+ ///
+ /// Used to instantiate each repository type
+ ///
+ public class RepositoryInstanceFactory
+ {
+
+ [RepositoryInstanceType(typeof(IUserTypeRepository))]
+ internal virtual IUserTypeRepository CreateUserTypeRepository(IUnitOfWork uow)
+ {
+ return new UserTypeRepository(
+ uow,
+ NullCacheProvider.Current);
+
+ }
+
+ [RepositoryInstanceType(typeof(IUserRepository))]
+ internal virtual IUserRepository CreateUserRepository(IUnitOfWork uow)
+ {
+ return new UserRepository(
+ uow,
+ NullCacheProvider.Current,
+ CreateUserTypeRepository(uow));
+
+ }
+
+ [RepositoryInstanceType(typeof(IContentRepository))]
+ public virtual IContentRepository CreateContentRepository(IUnitOfWork uow)
+ {
+ return new ContentRepository(
+ uow,
+ RuntimeCacheProvider.Current,
+ CreateContentTypeRepository(uow),
+ CreateTemplateRepository(uow));
+ }
+
+ [RepositoryInstanceType(typeof(IContentTypeRepository))]
+ public virtual IContentTypeRepository CreateContentTypeRepository(IUnitOfWork uow)
+ {
+ return new ContentTypeRepository(
+ uow,
+ InMemoryCacheProvider.Current,
+ new TemplateRepository(uow, NullCacheProvider.Current));
+ }
+
+ [RepositoryInstanceType(typeof(IDataTypeDefinitionRepository))]
+ public virtual IDataTypeDefinitionRepository CreateDataTypeDefinitionRepository(IUnitOfWork uow)
+ {
+ return new DataTypeDefinitionRepository(
+ uow,
+ NullCacheProvider.Current);
+ }
+
+ //TODO: Shouldn't IDictionaryRepository be public?
+ [RepositoryInstanceType(typeof(IDictionaryRepository))]
+ internal virtual IDictionaryRepository CreateDictionaryRepository(IUnitOfWork uow)
+ {
+ return new DictionaryRepository(
+ uow,
+ InMemoryCacheProvider.Current,
+ CreateLanguageRepository(uow));
+ }
+
+ [RepositoryInstanceType(typeof(ILanguageRepository))]
+ public virtual ILanguageRepository CreateLanguageRepository(IUnitOfWork uow)
+ {
+ return new LanguageRepository(
+ uow,
+ InMemoryCacheProvider.Current);
+ }
+
+ //TODO: Shouldn't IMacroRepository be public?
+ [RepositoryInstanceType(typeof(IMacroRepository))]
+ internal virtual IMacroRepository CreateMacroRepository(IUnitOfWork uow)
+ {
+ return new MacroRepository(
+ uow,
+ InMemoryCacheProvider.Current);
+ }
+
+ [RepositoryInstanceType(typeof(IMediaRepository))]
+ public virtual IMediaRepository CreateMediaRepository(IUnitOfWork uow)
+ {
+ return new MediaRepository(
+ uow,
+ RuntimeCacheProvider.Current,
+ CreateMediaTypeRepository(uow));
+ }
+
+ [RepositoryInstanceType(typeof(IMediaTypeRepository))]
+ public virtual IMediaTypeRepository CreateMediaTypeRepository(IUnitOfWork uow)
+ {
+ return new MediaTypeRepository(
+ uow,
+ InMemoryCacheProvider.Current);
+ }
+
+ [RepositoryInstanceType(typeof(IRelationRepository))]
+ public virtual IRelationRepository CreateRelationRepository(IUnitOfWork uow)
+ {
+ return new RelationRepository(
+ uow,
+ NullCacheProvider.Current,
+ CreateRelationTypeRepository(uow));
+ }
+
+ [RepositoryInstanceType(typeof(IRelationTypeRepository))]
+ public virtual IRelationTypeRepository CreateRelationTypeRepository(IUnitOfWork uow)
+ {
+ return new RelationTypeRepository(
+ uow,
+ NullCacheProvider.Current);
+ }
+
+ [RepositoryInstanceType(typeof(IScriptRepository))]
+ public virtual IScriptRepository CreateScriptRepository(IUnitOfWork uow)
+ {
+ return new ScriptRepository(uow);
+ }
+
+ [RepositoryInstanceType(typeof(IStylesheetRepository))]
+ public virtual IStylesheetRepository CreateStylesheetRepository(IUnitOfWork uow)
+ {
+ return new StylesheetRepository(uow);
+ }
+
+ [RepositoryInstanceType(typeof(ITemplateRepository))]
+ public virtual ITemplateRepository CreateTemplateRepository(IUnitOfWork uow)
+ {
+ return new TemplateRepository(uow, NullCacheProvider.Current);
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/RepositoryInstanceResolver.cs b/src/Umbraco.Core/Persistence/RepositoryInstanceResolver.cs
new file mode 100644
index 0000000000..e0c12ae299
--- /dev/null
+++ b/src/Umbraco.Core/Persistence/RepositoryInstanceResolver.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Linq;
+using System.Reflection;
+using Umbraco.Core.ObjectResolution;
+using Umbraco.Core.Persistence.UnitOfWork;
+
+namespace Umbraco.Core.Persistence
+{
+ ///
+ /// A resolver used to return the current implementation of the RepositoryInstanceFactory
+ ///
+ internal class RepositoryInstanceResolver : SingleObjectResolverBase
+ {
+ internal RepositoryInstanceResolver(RepositoryInstanceFactory registrar)
+ : base(registrar)
+ {
+ }
+
+ ///
+ /// Return the repository based on the type
+ ///
+ ///
+ ///
+ ///
+ internal TRepository ResolveByType(IUnitOfWork unitOfWork)
+ {
+ //TODO: REMOVE all of these binding flags once the IDictionaryRepository, IMacroRepository are public! As this probably
+ // wont work in medium trust!
+ var createMethod = this.Value.GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public)
+ .First(x => x.GetCustomAttributes(true).OfType()
+ .Any(instance => instance.InterfaceType.IsType()));
+ if (createMethod.GetParameters().Count() != 1
+ || !createMethod.GetParameters().Single().ParameterType.IsType())
+ {
+ throw new FormatException("The method " + createMethod.Name + " must only contain one parameter of type " + typeof(IUnitOfWork).FullName);
+ }
+ if (!createMethod.ReturnType.IsType())
+ {
+ throw new FormatException("The method " + createMethod.Name + " must return the type " + typeof(TRepository).FullName);
+ }
+
+ return (TRepository) createMethod.Invoke(this.Value, new object[] {unitOfWork});
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/RepositoryInstanceTypeAttribute.cs b/src/Umbraco.Core/Persistence/RepositoryInstanceTypeAttribute.cs
new file mode 100644
index 0000000000..4dc7fddcf1
--- /dev/null
+++ b/src/Umbraco.Core/Persistence/RepositoryInstanceTypeAttribute.cs
@@ -0,0 +1,23 @@
+using System;
+
+namespace Umbraco.Core.Persistence
+{
+ ///
+ /// Used to decorate each method of the class RepositoryInstanceFactory (or derived classes) to inform the system of what
+ /// type of Repository the method will be returning.
+ ///
+ ///
+ /// The reason for this attribute is because the RepositoryInstanceFactory (or derived classes) might contain methods multiple
+ /// methods that return the interface repository being asked for so we cannot simply rely on the return type of the methods.
+ ///
+ [AttributeUsage(AttributeTargets.Method)]
+ public class RepositoryInstanceTypeAttribute : Attribute
+ {
+ public Type InterfaceType { get; private set; }
+
+ public RepositoryInstanceTypeAttribute(Type interfaceType)
+ {
+ InterfaceType = interfaceType;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/RepositoryResolver.cs b/src/Umbraco.Core/Persistence/RepositoryResolver.cs
index 50bd73dfd3..ce1a6ae31e 100644
--- a/src/Umbraco.Core/Persistence/RepositoryResolver.cs
+++ b/src/Umbraco.Core/Persistence/RepositoryResolver.cs
@@ -10,7 +10,7 @@ using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Persistence
{
- internal class RepositoryResolver
+ internal class RepositoryResolver
{
private static readonly ConcurrentDictionary Repositories = new ConcurrentDictionary();
@@ -32,47 +32,52 @@ namespace Umbraco.Core.Persistence
string interfaceShortName = typeof(TRepository).Name;
string entityTypeName = typeof(TEntity).Name;
- //Check if the repository has already been created and is in the cache
- if (Repositories.ContainsKey(interfaceShortName))
- {
- repository = (TRepository)Repositories[interfaceShortName];
- if (unitOfWork != null && (typeof(IRepository).IsInstanceOfType(repository)))
- {
- repository.SetUnitOfWork(unitOfWork);
- }
- return repository;
- }
-
- var settings = Infrastructure.Instance.Repositories;
+ //Check if the repository has already been created and is in the cache
+ //SD: Changed to TryGetValue as this will be a bit quicker since if we do a ContainsKey and then resolve,
+ // the underlying ConcurrentDictionary does this twice and thus does two locks.
+ object repositoryObject;
+ if (Repositories.TryGetValue(interfaceShortName, out repositoryObject))
+ {
+ repository = (TRepository)repositoryObject;
+ if (unitOfWork != null && (typeof(IRepository).IsInstanceOfType(repository)))
+ {
+ repository.SetUnitOfWork(unitOfWork);
+ }
+ return repository;
+ }
- Type repositoryType = null;
+ repository = RepositoryInstanceResolver.Current.ResolveByType(unitOfWork);
- //Check if a valid interfaceShortName was passed in
- if (settings.Repository.ContainsKey(interfaceShortName))
- {
- repositoryType = Type.GetType(settings.Repository[interfaceShortName].RepositoryFullTypeName);
- }
- else
- {
- foreach (Repository element in settings.Repository)
- {
- if (element.InterfaceShortTypeName.Contains(entityTypeName))
- {
- repositoryType = Type.GetType(settings.Repository[element.InterfaceShortTypeName].RepositoryFullTypeName);
- break;
- }
- }
- }
+ //var settings = Infrastructure.Instance.Repositories;
- //If the repository type is null we should stop and throw an exception
- if (repositoryType == null)
- {
- throw new Exception(string.Format("No repository matching the Repository interface '{0}' or Entity type '{1}' could be resolved",
- interfaceShortName, entityTypeName));
- }
+ //Type repositoryType = null;
- //Resolve the repository with its constructor dependencies
- repository = Resolve(repositoryType, unitOfWork, interfaceShortName) as TRepository;
+ ////Check if a valid interfaceShortName was passed in
+ //if (settings.Repository.ContainsKey(interfaceShortName))
+ //{
+ // repositoryType = Type.GetType(settings.Repository[interfaceShortName].RepositoryFullTypeName);
+ //}
+ //else
+ //{
+ // foreach (Repository element in settings.Repository)
+ // {
+ // if (element.InterfaceShortTypeName.Contains(entityTypeName))
+ // {
+ // repositoryType = Type.GetType(settings.Repository[element.InterfaceShortTypeName].RepositoryFullTypeName);
+ // break;
+ // }
+ // }
+ //}
+
+ ////If the repository type is null we should stop and throw an exception
+ //if (repositoryType == null)
+ //{
+ // throw new Exception(string.Format("No repository matching the Repository interface '{0}' or Entity type '{1}' could be resolved",
+ // interfaceShortName, entityTypeName));
+ //}
+
+ ////Resolve the repository with its constructor dependencies
+ //repository = Resolve(repositoryType, unitOfWork, interfaceShortName) as TRepository;
//Add the new repository instance to the cache
Repositories.AddOrUpdate(interfaceShortName, repository, (x, y) => repository);
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 3717354a71..710f94fbbf 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -383,6 +383,9 @@
+
+
+
diff --git a/src/Umbraco.Tests/CodeFirst/CodeFirstTests.cs b/src/Umbraco.Tests/CodeFirst/CodeFirstTests.cs
index 348b3ba254..659243a258 100644
--- a/src/Umbraco.Tests/CodeFirst/CodeFirstTests.cs
+++ b/src/Umbraco.Tests/CodeFirst/CodeFirstTests.cs
@@ -228,8 +228,11 @@ namespace Umbraco.Tests.CodeFirst
[TearDown]
public override void TearDown()
{
+
DatabaseContext.Database.Dispose();
+ base.TearDown();
+
//reset the app context
DataTypesResolver.Reset();
ApplicationContext.Current = null;
diff --git a/src/Umbraco.Tests/Persistence/RepositoryInstanceResolverTests.cs b/src/Umbraco.Tests/Persistence/RepositoryInstanceResolverTests.cs
new file mode 100644
index 0000000000..f48775e7d1
--- /dev/null
+++ b/src/Umbraco.Tests/Persistence/RepositoryInstanceResolverTests.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Reflection;
+using NUnit.Framework;
+using Umbraco.Core;
+using Umbraco.Core.Persistence;
+using Umbraco.Core.Persistence.Repositories;
+using Umbraco.Core.Persistence.UnitOfWork;
+
+namespace Umbraco.Tests.Persistence
+{
+ [TestFixture]
+ public class RepositoryInstanceResolverTests
+ {
+ [SetUp]
+ public void Setup()
+ {
+ RepositoryInstanceResolver.Current = new RepositoryInstanceResolver(
+ new RepositoryInstanceFactory());
+ }
+
+ [TearDown]
+ public void Teardown()
+ {
+ RepositoryInstanceResolver.Reset();
+ }
+
+ [TestCase(typeof(IUserTypeRepository))]
+ [TestCase(typeof(IUserRepository))]
+ [TestCase(typeof(IContentRepository))]
+ [TestCase(typeof(IMediaRepository))]
+ [TestCase(typeof(IMediaTypeRepository))]
+ [TestCase(typeof(IContentTypeRepository))]
+ [TestCase(typeof(IDataTypeDefinitionRepository))]
+ [TestCase(typeof(IDictionaryRepository))]
+ [TestCase(typeof(ILanguageRepository))]
+ [TestCase(typeof(IMacroRepository))]
+ [TestCase(typeof(IRelationRepository))]
+ [TestCase(typeof(IRelationTypeRepository))]
+ [TestCase(typeof(IScriptRepository))]
+ [TestCase(typeof(IStylesheetRepository))]
+ [TestCase(typeof(ITemplateRepository))]
+ public void ResolveRepository(Type repoType)
+ {
+ var method = typeof (RepositoryInstanceResolver).GetMethod("ResolveByType", BindingFlags.NonPublic | BindingFlags.Instance);
+ var gMethod = method.MakeGenericMethod(repoType);
+ var repo = gMethod.Invoke(RepositoryInstanceResolver.Current, new object[] {new PetaPocoUnitOfWork()});
+ Assert.IsNotNull(repo);
+ Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(repoType, repo.GetType()));
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Tests/Persistence/RepositoryResolverTests.cs b/src/Umbraco.Tests/Persistence/RepositoryResolverTests.cs
index 90fee938bd..777ca27a93 100644
--- a/src/Umbraco.Tests/Persistence/RepositoryResolverTests.cs
+++ b/src/Umbraco.Tests/Persistence/RepositoryResolverTests.cs
@@ -7,9 +7,23 @@ using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Tests.Persistence
{
- [TestFixture]
+ [TestFixture]
public class RepositoryResolverTests
{
+
+ [SetUp]
+ public void Setup()
+ {
+ RepositoryInstanceResolver.Current = new RepositoryInstanceResolver(
+ new RepositoryInstanceFactory());
+ }
+
+ [TearDown]
+ public void Teardown()
+ {
+ RepositoryInstanceResolver.Reset();
+ }
+
[Test]
public void Can_Resolve_All_Repositories()
{
diff --git a/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs b/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs
index 7198fe502f..a77cdb35aa 100644
--- a/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs
+++ b/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs
@@ -35,7 +35,10 @@ namespace Umbraco.Tests.TestHelpers
AppDomain.CurrentDomain.SetData("DataDirectory", path);
UmbracoSettings.UseLegacyXmlSchema = false;
-
+
+ RepositoryInstanceResolver.Current = new RepositoryInstanceResolver(
+ new RepositoryInstanceFactory());
+
//Delete database file before continueing
string filePath = string.Concat(path, "\\UmbracoPetaPocoTests.sdf");
if (File.Exists(filePath))
@@ -74,6 +77,8 @@ namespace Umbraco.Tests.TestHelpers
ServiceContext = null;
Resolution.IsFrozen = false;
+ RepositoryInstanceResolver.Reset();
+
string path = TestHelper.CurrentAssemblyDirectory;
AppDomain.CurrentDomain.SetData("DataDirectory", null);
diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj
index 7ae3071121..160221e426 100644
--- a/src/Umbraco.Tests/Umbraco.Tests.csproj
+++ b/src/Umbraco.Tests/Umbraco.Tests.csproj
@@ -167,6 +167,7 @@
+