Files
Umbraco-CMS/src/Umbraco.Core/Persistence/RepositoryResolver.cs

184 lines
8.3 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Umbraco.Core.Configuration.InfrastructureSettings;
using Umbraco.Core.Persistence.Caching;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Persistence
{
internal class RepositoryResolver
{
private static readonly ConcurrentDictionary<string, object> Repositories = new ConcurrentDictionary<string, object>();
//GetRepository based on Repository Interface and Model Entity.
//Check if Dictionary contains the interface name of the Repository, ea. IContentRepository
//- If it does return the repository from the dictionary and set the new UnitOfWork object
//Otherwise look for the full type for the repository in config
//- If type exists check depedencies, create new object, add it to dictionary and return it
//Otherwise look for an entity type in the config
//- If type exists check dependencies, create new object, add it to dictionary and return it
//If we have come this far the correct types wasn't found and we throw an exception
internal static TRepository ResolveByType<TRepository>(IUnitOfWork unitOfWork)
where TRepository : class, IRepository
{
//Initialize the provider's default value
var repository = default(TRepository);
var interfaceShortName = typeof(TRepository).Name;
//string entityTypeName = typeof(TEntity).Name;
//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)
{
repository.SetUnitOfWork(unitOfWork);
}
return repository;
}
repository = RepositoryInstanceResolver.Current.ResolveByType<TRepository>(unitOfWork);
//var settings = Infrastructure.Instance.Repositories;
//Type repositoryType = null;
////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);
return repository;
}
//Recursive create and dependency check
private static object Resolve(Type repositoryType, IUnitOfWork unitOfWork, string interfaceShortName)
{
var constructors = repositoryType.GetConstructors();
var constructor = constructors.LastOrDefault();
if (constructor == null)
{
throw new Exception(string.Format("No public constructor was found on {0}", repositoryType.FullName));
}
var constructorArgs = new List<object>();
var settings = Infrastructure.Instance.Repositories;
var parameters = constructor.GetParameters();
foreach (var parameter in parameters)
{
if (parameter.ParameterType.Name.Equals("IUnitOfWork"))
{
constructorArgs.Add(unitOfWork);
}
else if (Repositories.ContainsKey(parameter.ParameterType.Name))
{
var repo = Repositories[parameter.ParameterType.Name];
constructorArgs.Add(repo);
}
else if(parameter.ParameterType.Name.Equals(typeof(IRepositoryCacheProvider).Name))
{
//Get the Type of the cache provider and activate the singleton instance
var cacheType = Type.GetType(settings.Repository[interfaceShortName].CacheProviderFullTypeName);
if (cacheType == null)
throw new Exception(string.Format("Unable to get the type of cache provider '{0}' from configuration while creating an instance of {1}",
settings.Repository[parameter.ParameterType.Name].
CacheProviderFullTypeName,
parameter.ParameterType.Name));
var cacheProvider = cacheType.InvokeMember("Current", BindingFlags.GetProperty, null, cacheType, new object[0]);
constructorArgs.Add(cacheProvider);
}
else
{
if (settings.Repository.ContainsKey(parameter.ParameterType.Name))
{
//Get the Type of the repository and resolve the object
var repoType = Type.GetType(settings.Repository[parameter.ParameterType.Name].RepositoryFullTypeName);
var repo = Resolve(repoType, unitOfWork, parameter.ParameterType.Name);
// Add the new repository instance to the cache
Repositories.AddOrUpdate(parameter.ParameterType.Name, repo, (x, y) => repo);
//Add the new repository to the constructor
constructorArgs.Add(repo);
}
else
{
throw new Exception("Cannot create the Repository. There was one or more invalid repository configuration settings.");
}
}
}
if (parameters.Count() != constructorArgs.Count)
throw new Exception(
string.Format(
"The amount of expected parameters is different from the amount of constructed parameters, which is confusing! Repository of type '{0}' could not be created.",
repositoryType.FullName));
var repositoryObj = Activator.CreateInstance(repositoryType, constructorArgs.ToArray());
return repositoryObj;
}
/// <summary>
/// Register all repositories by interating the configuration and adding the repositories to the internal cache (Dictionary)
/// </summary>
internal static void RegisterRepositories()
{
var settings = Infrastructure.Instance.Repositories;
foreach (Repository element in settings.Repository)
{
if (Repositories.ContainsKey(element.InterfaceShortTypeName)) continue;
var repositoryType = Type.GetType(settings.Repository[element.InterfaceShortTypeName].RepositoryFullTypeName);
var repository = Resolve(repositoryType, null, element.InterfaceShortTypeName);
//Add the new repository instance to the cache
Repositories.AddOrUpdate(element.InterfaceShortTypeName, repository, (x, y) => repository);
}
}
/// <summary>
/// Returns the number of repositories that has been registered
/// </summary>
/// <returns></returns>
internal static int RegisteredRepositories()
{
return Repositories.Count;
}
}
}