diff --git a/src/Umbraco.Core/Properties/AssemblyInfo.cs b/src/Umbraco.Core/Properties/AssemblyInfo.cs index 57c9864311..f58744b9f5 100644 --- a/src/Umbraco.Core/Properties/AssemblyInfo.cs +++ b/src/Umbraco.Core/Properties/AssemblyInfo.cs @@ -42,4 +42,5 @@ using System.Security.Permissions; [assembly: InternalsVisibleTo("Umbraco.Courier.Persistence")] [assembly: InternalsVisibleTo("Concorde.Sync")] -[assembly: InternalsVisibleTo("Umbraco.Belle")] \ No newline at end of file +[assembly: InternalsVisibleTo("Umbraco.Belle")] +[assembly: InternalsVisibleTo("Umbraco.VisualStudio")] \ No newline at end of file diff --git a/src/Umbraco.Core/Services/ServiceContext.cs b/src/Umbraco.Core/Services/ServiceContext.cs index 58ff6042f7..dbd50d7677 100644 --- a/src/Umbraco.Core/Services/ServiceContext.cs +++ b/src/Umbraco.Core/Services/ServiceContext.cs @@ -165,7 +165,7 @@ namespace Umbraco.Core.Services } /// - /// Gets the + /// Gets the /// internal IUserService UserService { diff --git a/src/Umbraco.Core/Standalone/ServiceContextManager.cs b/src/Umbraco.Core/Standalone/ServiceContextManager.cs new file mode 100644 index 0000000000..29a2945edd --- /dev/null +++ b/src/Umbraco.Core/Standalone/ServiceContextManager.cs @@ -0,0 +1,54 @@ +using System; +using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.Mappers; +using Umbraco.Core.Persistence.UnitOfWork; +using Umbraco.Core.Publishing; +using Umbraco.Core.Services; + +namespace Umbraco.Core.Standalone +{ + internal class ServiceContextManager : IDisposable + { + private readonly string _connectionString; + private readonly string _providerName; + private ServiceContext _serviceContext; + private readonly StandaloneCoreApplication _application; + + public ServiceContextManager(string connectionString, string providerName) + { + _connectionString = connectionString; + _providerName = providerName; + + _application = StandaloneCoreApplication.GetApplication(); + _application.Start(); + } + + public ServiceContext Services + { + get + { + if (_serviceContext == null) + { + var dbFactory = new DefaultDatabaseFactory(_connectionString, _providerName); + var dbContext = new DatabaseContext(dbFactory); + Database.Mapper = new PetaPocoMapper(); + _serviceContext = new ServiceContext( + new PetaPocoUnitOfWorkProvider(dbFactory), + new FileUnitOfWorkProvider(), + new PublishingStrategy()); + + //initialize the DatabaseContext + dbContext.Initialize(_providerName); + } + + return _serviceContext; + } + } + + public void Dispose() + { + ((IDisposable)ApplicationContext.Current).Dispose(); + _application.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Standalone/StandaloneCoreApplication.cs b/src/Umbraco.Core/Standalone/StandaloneCoreApplication.cs new file mode 100644 index 0000000000..0e0081d948 --- /dev/null +++ b/src/Umbraco.Core/Standalone/StandaloneCoreApplication.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; + +namespace Umbraco.Core.Standalone +{ + internal class StandaloneCoreApplication : UmbracoApplicationBase + { + /// + /// Initializes a new instance of the class. + /// + protected StandaloneCoreApplication() { } + + /// + /// Provides the application boot manager. + /// + /// An application boot manager. + protected override IBootManager GetBootManager() + { + return new StandaloneCoreBootManager(this, _handlersToAdd, _handlersToRemove); + } + + #region Application + + private static StandaloneCoreApplication _application; + private static bool _started; + private static readonly object AppLock = new object(); + + /// + /// Gets the instance of the standalone Umbraco application. + /// + public static StandaloneCoreApplication GetApplication() + { + lock (AppLock) + { + return _application ?? (_application = new StandaloneCoreApplication()); + } + } + + /// + /// Starts the application. + /// + public void Start() + { + lock (AppLock) + { + if (_started) + throw new InvalidOperationException("Application has already started."); + Application_Start(this, EventArgs.Empty); + _started = true; + } + } + + #endregion + + #region IApplicationEventHandler management + + private readonly List _handlersToAdd = new List(); + private readonly List _handlersToRemove = new List(); + + /// + /// Associates an type with the application. + /// + /// The type to associate. + /// The application. + /// Types implementing from within + /// an executable are not automatically discovered by Umbraco and have to be + /// explicitely associated with the application using this method. + public StandaloneCoreApplication WithApplicationEventHandler() + where T : IApplicationEventHandler + { + _handlersToAdd.Add(typeof(T)); + return this; + } + + /// + /// Dissociates an type from the application. + /// + /// The type to dissociate. + /// The application. + public StandaloneCoreApplication WithoutApplicationEventHandler() + where T : IApplicationEventHandler + { + _handlersToRemove.Add(typeof(T)); + return this; + } + + /// + /// Associates an type with the application. + /// + /// The type to associate. + /// The application. + /// Types implementing from within + /// an executable are not automatically discovered by Umbraco and have to be + /// explicitely associated with the application using this method. + public StandaloneCoreApplication WithApplicationEventHandler(Type type) + { + if (type.Implements() == false) + throw new ArgumentException("Type does not implement IApplicationEventHandler.", "type"); + _handlersToAdd.Add(type); + return this; + } + + /// + /// Dissociates an type from the application. + /// + /// The type to dissociate. + /// The application. + public StandaloneCoreApplication WithoutApplicationEventHandler(Type type) + { + if (type.Implements() == false) + throw new ArgumentException("Type does not implement IApplicationEventHandler.", "type"); + _handlersToRemove.Add(type); + return this; + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Standalone/StandaloneCoreBootManager.cs b/src/Umbraco.Core/Standalone/StandaloneCoreBootManager.cs new file mode 100644 index 0000000000..46871e2055 --- /dev/null +++ b/src/Umbraco.Core/Standalone/StandaloneCoreBootManager.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using Umbraco.Core.ObjectResolution; +using Umbraco.Core.Persistence.Mappers; +using umbraco.interfaces; + +namespace Umbraco.Core.Standalone +{ + internal class StandaloneCoreBootManager : CoreBootManager + { + private readonly IEnumerable _handlersToAdd; + private readonly IEnumerable _handlersToRemove; + + public StandaloneCoreBootManager(UmbracoApplicationBase umbracoApplication, IEnumerable handlersToAdd, IEnumerable handlersToRemove) + : base(umbracoApplication) + { + _handlersToAdd = handlersToAdd; + _handlersToRemove = handlersToRemove; + + // this is only here to ensure references to the assemblies needed for + // the DataTypesResolver otherwise they won't be loaded into the AppDomain. + var interfacesAssemblyName = typeof(IDataType).Assembly.FullName; + } + + protected override void InitializeApplicationEventsResolver() + { + base.InitializeApplicationEventsResolver(); + foreach (var type in _handlersToAdd) + ApplicationEventsResolver.Current.AddType(type); + foreach (var type in _handlersToRemove) + ApplicationEventsResolver.Current.RemoveType(type); + } + + protected override void InitializeResolvers() + { + base.InitializeResolvers(); + + //Mappers are not resolved, which could be because of a known TypeMapper issue + MappingResolver.Reset(); + MappingResolver.Current = new MappingResolver( + () => + new List + { + typeof (ContentMapper), + typeof (ContentTypeMapper), + typeof (MediaMapper), + typeof (MediaTypeMapper), + typeof (DataTypeDefinitionMapper), + typeof (UmbracoEntityMapper) + }); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index cd4f87dab4..a0dd3bb4f5 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -692,6 +692,9 @@ + + + diff --git a/src/Umbraco.Core/UmbracoApplicationBase.cs b/src/Umbraco.Core/UmbracoApplicationBase.cs index b08e0c9418..6962acdd07 100644 --- a/src/Umbraco.Core/UmbracoApplicationBase.cs +++ b/src/Umbraco.Core/UmbracoApplicationBase.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Web; using System.Web.Hosting; using System.Web.Mvc; diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs index 209c5e4313..4f0b1b0fe3 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs @@ -184,6 +184,32 @@ namespace Umbraco.Tests.Services Assert.That(homeDoc.ContentTypeId, Is.EqualTo(ctHomePage.Id)); } + [Test] + public void Can_Create_And_Save_ContentType_Composition() + { + /* + * Global + * - Components + * - Category + */ + var service = ServiceContext.ContentTypeService; + var global = MockedContentTypes.CreateSimpleContentType("global", "Global"); + service.Save(global); + + var components = MockedContentTypes.CreateSimpleContentType("components", "Components", global); + service.Save(components); + + var component = MockedContentTypes.CreateSimpleContentType("component", "Component", components); + service.Save(component); + + var category = MockedContentTypes.CreateSimpleContentType("category", "Category", global); + service.Save(category); + + var success = category.AddContentType(component); + + Assert.That(success, Is.False); + } + private IEnumerable CreateContentTypeHierarchy() { //create the master type diff --git a/src/Umbraco.Web/Standalone/ServiceContextManager.cs b/src/Umbraco.Web/Standalone/ServiceContextManager.cs new file mode 100644 index 0000000000..badd77d21b --- /dev/null +++ b/src/Umbraco.Web/Standalone/ServiceContextManager.cs @@ -0,0 +1,55 @@ +using System; +using Umbraco.Core; +using Umbraco.Core.Persistence; +using Umbraco.Core.Persistence.Mappers; +using Umbraco.Core.Persistence.UnitOfWork; +using Umbraco.Core.Publishing; +using Umbraco.Core.Services; + +namespace Umbraco.Web.Standalone +{ + internal class ServiceContextManager : IDisposable + { + private readonly string _connectionString; + private readonly string _providerName; + private ServiceContext _serviceContext; + private readonly StandaloneApplication _application; + + public ServiceContextManager(string connectionString, string providerName) + { + _connectionString = connectionString; + _providerName = providerName; + + _application = StandaloneApplication.GetApplication(); + _application.Start(); + } + + public ServiceContext Services + { + get + { + if (_serviceContext == null) + { + var dbFactory = new DefaultDatabaseFactory(_connectionString, _providerName); + var dbContext = new DatabaseContext(dbFactory); + Database.Mapper = new PetaPocoMapper(); + _serviceContext = new ServiceContext( + new PetaPocoUnitOfWorkProvider(dbFactory), + new FileUnitOfWorkProvider(), + new PublishingStrategy()); + + //initialize the DatabaseContext + dbContext.Initialize(_providerName); + } + + return _serviceContext; + } + } + + public void Dispose() + { + ((IDisposable)ApplicationContext.Current).Dispose(); + _application.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Standalone/StandaloneApplication.cs b/src/Umbraco.Web/Standalone/StandaloneApplication.cs index 7f08d3d9ef..a1fd0249a7 100644 --- a/src/Umbraco.Web/Standalone/StandaloneApplication.cs +++ b/src/Umbraco.Web/Standalone/StandaloneApplication.cs @@ -9,13 +9,12 @@ namespace Umbraco.Web.Standalone /// /// An application standalone applications. /// - class StandaloneApplication : UmbracoApplicationBase + internal class StandaloneApplication : UmbracoApplicationBase { /// /// Initializes a new instance of the class. /// - protected StandaloneApplication() - { } + protected StandaloneApplication(){ } /// /// Provides the application boot manager. diff --git a/src/Umbraco.Web/Standalone/StandaloneBootManager.cs b/src/Umbraco.Web/Standalone/StandaloneBootManager.cs index a10af65fe3..1215ab89a7 100644 --- a/src/Umbraco.Web/Standalone/StandaloneBootManager.cs +++ b/src/Umbraco.Web/Standalone/StandaloneBootManager.cs @@ -13,7 +13,7 @@ namespace Umbraco.Web.Standalone /// /// A boot manager for use in standalone applications. /// - class StandaloneBootManager : CoreBootManager + internal class StandaloneBootManager : CoreBootManager { // fixme - could we inherit from WebBootManager? // fixme - highly experimental, probably not complete! diff --git a/src/Umbraco.Web/Standalone/StandaloneHttpContext.cs b/src/Umbraco.Web/Standalone/StandaloneHttpContext.cs index c5089b7d78..4cf64a8adf 100644 --- a/src/Umbraco.Web/Standalone/StandaloneHttpContext.cs +++ b/src/Umbraco.Web/Standalone/StandaloneHttpContext.cs @@ -9,7 +9,7 @@ namespace Umbraco.Web.Standalone /// /// An Http context for use in standalone applications. /// - class StandaloneHttpContext : HttpContextBase + internal class StandaloneHttpContext : HttpContextBase { // fixme - what shall we implement here? diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index db3d3adc10..ece5c2a441 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -284,6 +284,7 @@ +