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; } } }