using System;
using System.Linq;
using LightInject;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Mappers;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.DependencyInjection
{
///
/// Sets the IoC container for the umbraco data layer/repositories/sql/database/etc...
///
public sealed class RepositoryCompositionRoot : ICompositionRoot
{
public void Compose(IServiceRegistry container)
{
container.RegisterSingleton(factory => new DefaultDatabaseFactory(GlobalSettings.UmbracoConnectionName, factory.GetInstance()));
container.RegisterSingleton(factory => GetDbContext(factory));
container.RegisterSingleton(factory => SqlSyntaxProviders.CreateDefault(factory.GetInstance()));
container.RegisterSingleton();
container.RegisterSingleton(factory => new PetaPocoUnitOfWorkProvider(factory.GetInstance()));
container.RegisterSingleton(factory => new MappingResolver(
factory.GetInstance(),
factory.GetInstance(),
() => factory.GetInstance().ResolveAssignedMapperTypes()));
container.Register();
container.Register(factory => factory.GetInstance().SqlSyntax);
container.RegisterSingleton(factory => CacheHelper.CreateDisabledCacheHelper(), "DisabledCache");
container.RegisterSingleton(factory => new PhysicalFileSystem(SystemDirectories.Scripts), "ScriptFileSystem");
container.RegisterSingleton(factory => new PhysicalFileSystem(SystemDirectories.MvcViews + "/Partials/"), "PartialViewFileSystem");
container.RegisterSingleton(factory => new PhysicalFileSystem(SystemDirectories.MvcViews + "/MacroPartials/"), "PartialViewMacroFileSystem");
container.RegisterSingleton(factory => new PhysicalFileSystem(SystemDirectories.Css), "StylesheetFileSystem");
container.RegisterSingleton(factory => new PhysicalFileSystem(SystemDirectories.Masterpages), "MasterpageFileSystem");
container.RegisterSingleton(factory => new PhysicalFileSystem(SystemDirectories.MvcViews), "ViewFileSystem");
//Repository factories:
//NOTE: Wondering if we can pass in parameters at resolution time with LightInject
// without having to manually specify the ctor for each one, have asked here: https://github.com/seesharper/LightInject/issues/237
container.Register((factory, work) => new NotificationsRepository(work, factory.GetInstance()));
container.Register((factory, work) => new ExternalLoginRepository(
work,
factory.GetInstance(),
factory.GetInstance(),
factory.GetInstance(),
factory.GetInstance()));
//here we are using some nice IoC magic:
//https://github.com/seesharper/LightInject/issues/237
//This tells the container that anytime there is a ctor dependency for IDatabaseUnitOfWork and it's available as the first
//arg in the runtimeArgs, to use that. This means we donn't have to explicitly define all ctor's for all repositories which
//saves us a lot of code.
container.RegisterConstructorDependency((factory, info, runtimeArguments) =>
{
var uow = runtimeArguments.Length > 0 ? runtimeArguments[0] as IDatabaseUnitOfWork : null;
return uow;
});
//This ensures that the correct CacheHelper is returned for the right repos
container.RegisterConstructorDependency((factory, info, runtimeArguments) =>
{
var declaringType = info.Member.DeclaringType;
var disabledCacheRepos = new[]
{
typeof (ITaskRepository),
typeof (ITaskTypeRepository),
typeof (IAuditRepository),
typeof (IRelationRepository),
typeof (IRelationTypeRepository),
typeof (IAuditRepository),
typeof (IMigrationEntryRepository)
};
return disabledCacheRepos.Any(x => TypeHelper.IsTypeAssignableFrom(x, declaringType))
? factory.GetInstance("DisabledCache")
: factory.GetInstance();
});
container.Register();
container.Register();
container.Register();
container.Register();
container.Register();
container.Register();
container.Register();
container.Register();
container.Register();
container.Register();
container.Register();
container.Register();
container.Register();
container.Register();
container.Register();
container.Register();
container.Register();
container.Register();
container.Register();
container.Register();
container.Register();
container.Register();
container.Register();
container.Register();
container.Register();
//These repo registrations require custom injections so we need to define them:
container.Register((factory, work) => new ServerRegistrationRepository(
work,
factory.GetInstance().StaticCache, //special static cache scenario
factory.GetInstance(),
factory.GetInstance(),
factory.GetInstance()));
container.Register((factory, work) => new ScriptRepository(
work,
factory.GetInstance("ScriptFileSystem"),
factory.GetInstance()));
container.Register((factory, work) => new PartialViewRepository(
work,
factory.GetInstance("ScriptFileSystem")),
serviceName: "PartialViewFileSystem");
container.Register((factory, work) => new PartialViewMacroRepository(
work,
factory.GetInstance("PartialViewMacroFileSystem")),
serviceName: "PartialViewMacroRepository");
container.Register((factory, work) => new StylesheetRepository(
work,
factory.GetInstance("StylesheetFileSystem")));
}
///
/// Creates and initializes the db context when IoC requests it
///
///
///
private DatabaseContext GetDbContext(IServiceFactory container)
{
var dbCtx = new DatabaseContext(
container.GetInstance(),
container.GetInstance(),
container.GetInstance());
//when it's first created we need to initialize it
dbCtx.Initialize();
return dbCtx;
}
}
}