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 @@
+