Changed all data services to create one repository type in the constructor instead of resolving
them in each method since they are only supposed to be using their single unit of work anyways (resolving will return the same repository anyways, but in some cases it might have been with a different UOW) Removed SetUnitOfWork method on IRepository as this is not needed. Removed the old implementation of RepositoryResolver and replaces it with the RepositoryInstanceResolver (but maintained the name of RepositoryResolver)
This commit is contained in:
@@ -1,184 +1,65 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Umbraco.Core.Configuration.InfrastructureSettings;
|
||||
using Umbraco.Core.Persistence.Caching;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
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>();
|
||||
/// <summary>
|
||||
/// A resolver used to return the current implementation of the RepositoryInstanceFactory
|
||||
/// </summary>
|
||||
internal class RepositoryResolver : SingleObjectResolverBase<RepositoryResolver, RepositoryFactory>
|
||||
{
|
||||
internal RepositoryResolver(RepositoryFactory registrar)
|
||||
: base(registrar)
|
||||
{
|
||||
}
|
||||
|
||||
//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);
|
||||
/// <summary>
|
||||
/// Can be used by developers at runtime to set their own RepositoryInstanceFactory at app startup
|
||||
/// </summary>
|
||||
/// <param name="factory"></param>
|
||||
public void SetRepositoryInstanceFactory(RepositoryFactory factory)
|
||||
{
|
||||
Value = factory;
|
||||
}
|
||||
|
||||
var interfaceShortName = typeof(TRepository).Name;
|
||||
//string entityTypeName = typeof(TEntity).Name;
|
||||
/// <summary>
|
||||
/// Returns the RepositoryInstanceFactory object
|
||||
/// </summary>
|
||||
internal RepositoryFactory Factory
|
||||
{
|
||||
get { return Value; }
|
||||
}
|
||||
|
||||
//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))
|
||||
/// <summary>
|
||||
/// Return the repository based on the type
|
||||
/// </summary>
|
||||
/// <typeparam name="TRepository"></typeparam>
|
||||
/// <param name="unitOfWork"></param>
|
||||
/// <returns></returns>
|
||||
internal TRepository ResolveByType<TRepository>(IUnitOfWork unitOfWork)
|
||||
where TRepository : class, IRepository
|
||||
{
|
||||
//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()
|
||||
.First(x => x.Name == "Create" + typeof (TRepository).Name.Substring(1));
|
||||
|
||||
if (createMethod.GetParameters().Count() != 1
|
||||
|| !createMethod.GetParameters().Single().ParameterType.IsType<IUnitOfWork>())
|
||||
{
|
||||
repository = (TRepository)repositoryObject;
|
||||
if (unitOfWork != null)
|
||||
{
|
||||
repository.SetUnitOfWork(unitOfWork);
|
||||
}
|
||||
return repository;
|
||||
throw new FormatException("The method " + createMethod.Name + " must only contain one parameter of type " + typeof(IUnitOfWork).FullName);
|
||||
}
|
||||
if (!createMethod.ReturnType.IsType<TRepository>())
|
||||
{
|
||||
throw new FormatException("The method " + createMethod.Name + " must return the type " + typeof(TRepository).FullName);
|
||||
}
|
||||
|
||||
repository = RepositoryInstanceResolver.Current.ResolveByType<TRepository>(unitOfWork);
|
||||
return (TRepository) createMethod.Invoke(this.Value, new object[] {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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user