diff --git a/src/Umbraco.Core/CallContextScope.cs b/src/Umbraco.Core/CallContextScope.cs
new file mode 100644
index 0000000000..1eb4589899
--- /dev/null
+++ b/src/Umbraco.Core/CallContextScope.cs
@@ -0,0 +1,25 @@
+using System.Runtime.Remoting.Messaging;
+
+namespace Umbraco.Core
+{
+ ///
+ /// A place to get/retrieve data in a current context (i.e. http, thread, etc...)
+ ///
+ internal class CallContextScope : IScopeContext
+ {
+ public object GetData(string key)
+ {
+ return CallContext.GetData(key);
+ }
+
+ public void SetData(string key, object data)
+ {
+ CallContext.SetData(key, data);
+ }
+
+ public void ClearData(string key)
+ {
+ CallContext.FreeNamedDataSlot(key);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/DefaultScopeContextFactory.cs b/src/Umbraco.Core/DefaultScopeContextFactory.cs
new file mode 100644
index 0000000000..1152ee6b41
--- /dev/null
+++ b/src/Umbraco.Core/DefaultScopeContextFactory.cs
@@ -0,0 +1,16 @@
+using System.Web;
+using Umbraco.Core.Persistence;
+
+namespace Umbraco.Core
+{
+ ///
+ /// Default scope context factory
+ ///
+ internal class DefaultScopeContextFactory : IScopeContextFactory
+ {
+ public IScopeContext GetContext()
+ {
+ return HttpContext.Current == null ? (IScopeContext)new CallContextScope() : new HttpContextScope();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/DependencyInjection/RepositoryCompositionRoot.cs b/src/Umbraco.Core/DependencyInjection/RepositoryCompositionRoot.cs
index d579eb7d57..58d22f4fee 100644
--- a/src/Umbraco.Core/DependencyInjection/RepositoryCompositionRoot.cs
+++ b/src/Umbraco.Core/DependencyInjection/RepositoryCompositionRoot.cs
@@ -23,6 +23,8 @@ namespace Umbraco.Core.DependencyInjection
container.Register("SqlCeSyntaxProvider");
container.Register("SqlServerSyntaxProvider");
+ container.RegisterSingleton();
+
// register database factory
// will be initialized with syntax providers and a logger, and will try to configure
// from the default connection string name, if possible, else will remain non-configured
diff --git a/src/Umbraco.Core/HttpContextScope.cs b/src/Umbraco.Core/HttpContextScope.cs
new file mode 100644
index 0000000000..594e5be964
--- /dev/null
+++ b/src/Umbraco.Core/HttpContextScope.cs
@@ -0,0 +1,25 @@
+using System.Web;
+
+namespace Umbraco.Core
+{
+ ///
+ /// A place to get/retrieve data in a current context (i.e. http, thread, etc...)
+ ///
+ internal class HttpContextScope : IScopeContext
+ {
+ public object GetData(string key)
+ {
+ return HttpContext.Current.Items[key];
+ }
+
+ public void SetData(string key, object data)
+ {
+ HttpContext.Current.Items[key] = data;
+ }
+
+ public void ClearData(string key)
+ {
+ HttpContext.Current.Items.Remove(key);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/IScopeContext.cs b/src/Umbraco.Core/IScopeContext.cs
new file mode 100644
index 0000000000..8a1a916acc
--- /dev/null
+++ b/src/Umbraco.Core/IScopeContext.cs
@@ -0,0 +1,12 @@
+namespace Umbraco.Core
+{
+ ///
+ /// A place to get/retrieve data in a current context (i.e. http, thread, etc...)
+ ///
+ internal interface IScopeContext
+ {
+ object GetData(string key);
+ void SetData(string key, object data);
+ void ClearData(string key);
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/IScopeContextFactory.cs b/src/Umbraco.Core/IScopeContextFactory.cs
new file mode 100644
index 0000000000..e402f23608
--- /dev/null
+++ b/src/Umbraco.Core/IScopeContextFactory.cs
@@ -0,0 +1,10 @@
+namespace Umbraco.Core
+{
+ ///
+ /// Gets an IScopedContext
+ ///
+ internal interface IScopeContextFactory
+ {
+ IScopeContext GetContext();
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/DefaultDatabaseFactory.cs b/src/Umbraco.Core/Persistence/DefaultDatabaseFactory.cs
index d51c1f97ae..fef60db1d7 100644
--- a/src/Umbraco.Core/Persistence/DefaultDatabaseFactory.cs
+++ b/src/Umbraco.Core/Persistence/DefaultDatabaseFactory.cs
@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Configuration;
using System.Data.Common;
using System.Linq;
-using System.Web;
+using System.Threading;
using NPoco;
using NPoco.FluentMappings;
using Umbraco.Core.Configuration;
@@ -26,11 +26,12 @@ namespace Umbraco.Core.Persistence
///
internal class DefaultDatabaseFactory : DisposableObject, IDatabaseFactory
{
+ private readonly IScopeContextFactory _scopeContextFactory;
private readonly ISqlSyntaxProvider[] _sqlSyntaxProviders;
- private readonly ILogger _logger;
- private bool _configured;
+ private readonly ILogger _logger;
- private DatabaseFactory _databaseFactory;
+ private const string HttpItemKey = "Umbraco.Core.Persistence.DefaultDatabaseFactory";
+ private DatabaseFactory _databaseFactory;
private IPocoDataFactory _pocoDataFactory;
private string _connectionString;
private string _providerName;
@@ -39,9 +40,9 @@ namespace Umbraco.Core.Persistence
private ISqlSyntaxProvider _sqlSyntax;
private RetryPolicy _connectionRetryPolicy;
private RetryPolicy _commandRetryPolicy;
+ private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
- // fixme - what needs to be private fields vs public properties?
- public bool Configured => _configured;
+ public bool Configured { get; private set; }
public ISqlSyntaxProvider SqlSyntax
{
get
@@ -51,20 +52,16 @@ namespace Umbraco.Core.Persistence
}
}
- // very important to have ThreadStatic,
- // see: http://issues.umbraco.org/issue/U4-2172
- [ThreadStatic]
- private static Lazy _nonHttpInstance;
-
///
/// Initializes a new instance of the with the default connection, and a logger.
///
/// The collection of available sql syntax providers.
/// A logger.
+ ///
/// Used by LightInject.
- public DefaultDatabaseFactory(IEnumerable sqlSyntaxProviders, ILogger logger)
- : this(GlobalSettings.UmbracoConnectionName, sqlSyntaxProviders, logger)
- {
+ public DefaultDatabaseFactory(IEnumerable sqlSyntaxProviders, ILogger logger, IScopeContextFactory scopeContextFactory)
+ : this(GlobalSettings.UmbracoConnectionName, sqlSyntaxProviders, logger, scopeContextFactory)
+ {
if (Configured == false)
DatabaseContext.GiveLegacyAChance(this, logger);
}
@@ -75,15 +72,20 @@ namespace Umbraco.Core.Persistence
/// The name of the connection string in web.config.
/// The collection of available sql syntax providers.
/// A logger
+ ///
/// Used by the other ctor and in tests.
- public DefaultDatabaseFactory(string connectionStringName, IEnumerable sqlSyntaxProviders, ILogger logger)
- {
+ public DefaultDatabaseFactory(string connectionStringName, IEnumerable sqlSyntaxProviders, ILogger logger, IScopeContextFactory scopeContextFactory)
+ {
if (sqlSyntaxProviders == null) throw new ArgumentNullException(nameof(sqlSyntaxProviders));
if (logger == null) throw new ArgumentNullException(nameof(logger));
+ if (scopeContextFactory == null) throw new ArgumentNullException(nameof(scopeContextFactory));
if (string.IsNullOrWhiteSpace(connectionStringName)) throw new ArgumentException("Value cannot be null nor empty.", nameof(connectionStringName));
_sqlSyntaxProviders = sqlSyntaxProviders.ToArray();
_logger = logger;
+ _scopeContextFactory = scopeContextFactory;
+
+ _logger.Debug("Created!");
var settings = ConfigurationManager.ConnectionStrings[connectionStringName];
if (settings == null)
@@ -97,61 +99,73 @@ namespace Umbraco.Core.Persistence
///
/// The database connection string.
/// The name of the database provider.
- /// The collection of available sql syntax providers.
+ /// The collection of available sql syntax providers.
/// A logger.
+ ///
/// Used in tests.
- public DefaultDatabaseFactory(string connectionString, string providerName, IEnumerable sqlSyntaxProviders, ILogger logger)
- {
+ public DefaultDatabaseFactory(string connectionString, string providerName, IEnumerable sqlSyntaxProviders, ILogger logger, IScopeContextFactory scopeContextFactory)
+ {
if (sqlSyntaxProviders == null) throw new ArgumentNullException(nameof(sqlSyntaxProviders));
if (logger == null) throw new ArgumentNullException(nameof(logger));
+ if (scopeContextFactory == null) throw new ArgumentNullException(nameof(scopeContextFactory));
_sqlSyntaxProviders = sqlSyntaxProviders.ToArray();
_logger = logger;
+ _scopeContextFactory = scopeContextFactory;
+
+ _logger.Debug("Created!");
if (string.IsNullOrWhiteSpace(connectionString) || string.IsNullOrWhiteSpace(providerName))
return; // not configured
Configure(connectionString, providerName);
- }
+ }
public void Configure(string connectionString, string providerName)
{
- if (_configured) throw new InvalidOperationException("Already configured.");
+ using (new WriteLock(_lock))
+ {
+ _logger.Debug("Configuring!");
- Mandate.ParameterNotNullOrEmpty(connectionString, nameof(connectionString));
- Mandate.ParameterNotNullOrEmpty(providerName, nameof(providerName));
+ if (Configured) throw new InvalidOperationException("Already configured.");
- _connectionString = connectionString;
- _providerName = providerName;
+ Mandate.ParameterNotNullOrEmpty(connectionString, nameof(connectionString));
+ Mandate.ParameterNotNullOrEmpty(providerName, nameof(providerName));
- _connectionRetryPolicy = RetryPolicyFactory.GetDefaultSqlConnectionRetryPolicyByConnectionString(_connectionString);
- _commandRetryPolicy = RetryPolicyFactory.GetDefaultSqlCommandRetryPolicyByConnectionString(_connectionString);
+ _connectionString = connectionString;
+ _providerName = providerName;
- _dbProviderFactory = DbProviderFactories.GetFactory(_providerName);
- if (_dbProviderFactory == null)
- throw new Exception($"Can't find a provider factory for provider name \"{_providerName}\".");
- _databaseType = DatabaseType.Resolve(_dbProviderFactory.GetType().Name, _providerName);
- if (_databaseType == null)
- throw new Exception($"Can't find an NPoco database type for provider name \"{_providerName}\".");
+ _connectionRetryPolicy = RetryPolicyFactory.GetDefaultSqlConnectionRetryPolicyByConnectionString(_connectionString);
+ _commandRetryPolicy = RetryPolicyFactory.GetDefaultSqlCommandRetryPolicyByConnectionString(_connectionString);
- _sqlSyntax = GetSqlSyntaxProvider(_providerName);
- if (_sqlSyntax == null)
- throw new Exception($"Can't find a sql syntax provider for provider name \"{_providerName}\".");
+ _dbProviderFactory = DbProviderFactories.GetFactory(_providerName);
+ if (_dbProviderFactory == null)
+ throw new Exception($"Can't find a provider factory for provider name \"{_providerName}\".");
+ _databaseType = DatabaseType.Resolve(_dbProviderFactory.GetType().Name, _providerName);
+ if (_databaseType == null)
+ throw new Exception($"Can't find an NPoco database type for provider name \"{_providerName}\".");
- // ensure we have only 1 set of mappers, and 1 PocoDataFactory, for all database
- // so that everything NPoco is properly cached for the lifetime of the application
- var mappers = new MapperCollection { new PocoMapper() };
- var factory = new FluentPocoDataFactory((type, iPocoDataFactory) => new PocoDataBuilder(type, mappers).Init());
- _pocoDataFactory = factory;
- var config = new FluentConfig(xmappers => factory);
+ _sqlSyntax = GetSqlSyntaxProvider(_providerName);
+ if (_sqlSyntax == null)
+ throw new Exception($"Can't find a sql syntax provider for provider name \"{_providerName}\".");
- // create the database factory
- _databaseFactory = DatabaseFactory.Config(x => x
- .UsingDatabase(CreateDatabaseInstance) // creating UmbracoDatabase instances
- .WithFluentConfig(config)); // with proper configuration
+ // ensure we have only 1 set of mappers, and 1 PocoDataFactory, for all database
+ // so that everything NPoco is properly cached for the lifetime of the application
+ var mappers = new MapperCollection { new PocoMapper() };
+ var factory = new FluentPocoDataFactory((type, iPocoDataFactory) => new PocoDataBuilder(type, mappers).Init());
+ _pocoDataFactory = factory;
+ var config = new FluentConfig(xmappers => factory);
- _nonHttpInstance = new Lazy(() => (UmbracoDatabase) _databaseFactory.GetDatabase());
- _configured = true;
+ // create the database factory
+ _databaseFactory = DatabaseFactory.Config(x => x
+ .UsingDatabase(CreateDatabaseInstance) // creating UmbracoDatabase instances
+ .WithFluentConfig(config)); // with proper configuration
+
+ if (_databaseFactory == null) throw new NullReferenceException("The call to DatabaseFactory.Config yielded a null DatabaseFactory instance");
+
+ _logger.Debug("Created _nonHttpInstance");
+ Configured = true;
+ }
}
// gets the sql syntax provider that corresponds, from attribute
@@ -174,19 +188,22 @@ namespace Umbraco.Core.Persistence
/// Gets a value indicating whether it is possible to connect to the database.
///
///
- public bool CanConnect => _configured && DbConnectionExtensions.IsConnectionAvailable(_connectionString, _providerName);
+ public bool CanConnect => Configured && DbConnectionExtensions.IsConnectionAvailable(_connectionString, _providerName);
private void EnsureConfigured()
{
- if (_configured == false)
- throw new InvalidOperationException("Not configured.");
+ using (new ReadLock(_lock))
+ {
+ if (Configured == false)
+ throw new InvalidOperationException("Not configured.");
+ }
}
// method used by NPoco's DatabaseFactory to actually create the database instance
private UmbracoDatabase CreateDatabaseInstance()
- {
- return new UmbracoDatabase(_connectionString, _sqlSyntax, _databaseType, _dbProviderFactory, _logger, _connectionRetryPolicy, _commandRetryPolicy);
- }
+ {
+ return new UmbracoDatabase(_connectionString, _sqlSyntax, _databaseType, _dbProviderFactory, _logger, _connectionRetryPolicy, _commandRetryPolicy);
+ }
///
/// Gets (creates or retrieves) the "ambient" database connection.
@@ -196,43 +213,29 @@ namespace Umbraco.Core.Persistence
{
EnsureConfigured();
- // no http context, create the thread-static singleton object
- if (HttpContext.Current == null)
- {
- return _nonHttpInstance.Value;
- }
+ var scope = _scopeContextFactory.GetContext();
- // we have an http context, so only create one per request
- var db = HttpContext.Current.Items[typeof (DefaultDatabaseFactory)] as UmbracoDatabase;
- if (db == null) HttpContext.Current.Items[typeof (DefaultDatabaseFactory)] = db = (UmbracoDatabase) _databaseFactory.GetDatabase();
- return db;
- }
-
- protected override void DisposeResources()
- {
+ // check if it's in scope
+ var db = scope.GetData(HttpItemKey) as UmbracoDatabase;
+ if (db != null) return db;
+ db = (UmbracoDatabase) _databaseFactory.GetDatabase();
+ scope.SetData(HttpItemKey, db);
+ return db;
+ }
+
+ protected override void DisposeResources()
+ {
// this is weird, because _nonHttpInstance is thread-static, so we would need
// to dispose the factory in each thread where a database has been used - else
// it only disposes the current thread's database instance.
//
// besides, we don't really want to dispose the factory, which is a singleton...
-
- UmbracoDatabase db = null;
-
- if (HttpContext.Current == null)
- {
- if (_nonHttpInstance.IsValueCreated)
- {
- db = _nonHttpInstance.Value;
- _nonHttpInstance = null;
- }
- }
- else
- {
- db = HttpContext.Current.Items[typeof(DefaultDatabaseFactory)] as UmbracoDatabase;
- HttpContext.Current.Items[typeof (DefaultDatabaseFactory)] = null;
- }
-
- db?.Dispose();
- }
- }
+
+ var scope = _scopeContextFactory.GetContext();
+ var db = scope.GetData(HttpItemKey) as UmbracoDatabase;
+ scope.ClearData(HttpItemKey);
+ db?.Dispose();
+ Configured = false;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/UnitOfWork/NPocoUnitOfWorkProvider.cs b/src/Umbraco.Core/Persistence/UnitOfWork/NPocoUnitOfWorkProvider.cs
index 156d1df224..dcea35cedb 100644
--- a/src/Umbraco.Core/Persistence/UnitOfWork/NPocoUnitOfWorkProvider.cs
+++ b/src/Umbraco.Core/Persistence/UnitOfWork/NPocoUnitOfWorkProvider.cs
@@ -38,7 +38,7 @@ namespace Umbraco.Core.Persistence.UnitOfWork
///
internal NPocoUnitOfWorkProvider(ILogger logger)
{
- _databaseFactory = new DefaultDatabaseFactory(GlobalSettings.UmbracoConnectionName, GetDefaultSqlSyntaxProviders(logger), logger);
+ _databaseFactory = new DefaultDatabaseFactory(GlobalSettings.UmbracoConnectionName, GetDefaultSqlSyntaxProviders(logger), logger, new DefaultScopeContextFactory());
// careful, _repositoryFactory remains null!
}
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index e5f5e0e7c6..aeacb4c613 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -377,10 +377,15 @@
+
+
Component
+
+
+
diff --git a/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs b/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs
index 3d1e4a268e..b1545f0c40 100644
--- a/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs
+++ b/src/Umbraco.Tests/Persistence/DatabaseContextTests.cs
@@ -31,7 +31,7 @@ namespace Umbraco.Tests.Persistence
_sqlCeSyntaxProvider = new SqlCeSyntaxProvider();
_sqlSyntaxProviders = new[] { (ISqlSyntaxProvider) _sqlCeSyntaxProvider };
_logger = Mock.Of();
- var dbFactory = new DefaultDatabaseFactory(Core.Configuration.GlobalSettings.UmbracoConnectionName, _sqlSyntaxProviders, _logger);
+ var dbFactory = new DefaultDatabaseFactory(Core.Configuration.GlobalSettings.UmbracoConnectionName, _sqlSyntaxProviders, _logger, new TestScopeContextFactory());
_dbContext = new DatabaseContext(dbFactory, _logger);
}
@@ -79,7 +79,7 @@ namespace Umbraco.Tests.Persistence
engine.CreateDatabase();
// re-create the database factory and database context with proper connection string
- var dbFactory = new DefaultDatabaseFactory(engine.LocalConnectionString, Constants.DbProviderNames.SqlCe, _sqlSyntaxProviders, _logger);
+ var dbFactory = new DefaultDatabaseFactory(engine.LocalConnectionString, Constants.DbProviderNames.SqlCe, _sqlSyntaxProviders, _logger, new TestScopeContextFactory());
_dbContext = new DatabaseContext(dbFactory, _logger);
// create application context
diff --git a/src/Umbraco.Tests/Persistence/FaultHandling/ConnectionRetryTest.cs b/src/Umbraco.Tests/Persistence/FaultHandling/ConnectionRetryTest.cs
index 1d5127db3d..5df66b1f54 100644
--- a/src/Umbraco.Tests/Persistence/FaultHandling/ConnectionRetryTest.cs
+++ b/src/Umbraco.Tests/Persistence/FaultHandling/ConnectionRetryTest.cs
@@ -6,6 +6,7 @@ using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.SqlSyntax;
+using Umbraco.Tests.TestHelpers;
namespace Umbraco.Tests.Persistence.FaultHandling
{
@@ -19,7 +20,7 @@ namespace Umbraco.Tests.Persistence.FaultHandling
const string connectionString = @"server=.\SQLEXPRESS;database=EmptyForTest;user id=x;password=umbraco";
const string providerName = Constants.DbProviderNames.SqlServer;
var sqlSyntax = new[] { new SqlServerSyntaxProvider(new Lazy(() => null)) };
- var factory = new DefaultDatabaseFactory(connectionString, providerName, sqlSyntax, Mock.Of());
+ var factory = new DefaultDatabaseFactory(connectionString, providerName, sqlSyntax, Mock.Of(), new TestScopeContextFactory());
var database = factory.GetDatabase();
//Act
@@ -34,7 +35,7 @@ namespace Umbraco.Tests.Persistence.FaultHandling
const string connectionString = @"server=.\SQLEXPRESS;database=EmptyForTest;user id=umbraco;password=umbraco";
const string providerName = Constants.DbProviderNames.SqlServer;
var sqlSyntax = new[] { new SqlServerSyntaxProvider(new Lazy(() => null)) };
- var factory = new DefaultDatabaseFactory(connectionString, providerName, sqlSyntax, Mock.Of());
+ var factory = new DefaultDatabaseFactory(connectionString, providerName, sqlSyntax, Mock.Of(), new TestScopeContextFactory());
var database = factory.GetDatabase();
//Act
diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs
index e3931c7068..9e2b21e3b6 100644
--- a/src/Umbraco.Tests/Services/ContentServiceTests.cs
+++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs
@@ -1333,7 +1333,11 @@ namespace Umbraco.Tests.Services
[Test]
public void Can_Save_Lazy_Content()
{
- var databaseFactory = new DefaultDatabaseFactory(Umbraco.Core.Configuration.GlobalSettings.UmbracoConnectionName, TestObjects.GetDefaultSqlSyntaxProviders(Logger), Logger);
+ var databaseFactory = new DefaultDatabaseFactory(
+ Umbraco.Core.Configuration.GlobalSettings.UmbracoConnectionName,
+ TestObjects.GetDefaultSqlSyntaxProviders(Logger),
+ Logger,
+ new TestScopeContextFactory());
var repositoryFactory = MockRepositoryFactory();
var provider = new NPocoUnitOfWorkProvider(databaseFactory, repositoryFactory);
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
diff --git a/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs b/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs
index 671c6e3f74..02a0888458 100644
--- a/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs
+++ b/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs
@@ -107,7 +107,7 @@ namespace Umbraco.Tests.TestHelpers
// use a mock factory; otherwise use a real factory.
var databaseFactory = DatabaseTestBehavior == DatabaseBehavior.NoDatabasePerFixture
? TestObjects.GetIDatabaseFactoryMock()
- : new DefaultDatabaseFactory(GetDbConnectionString(), GetDbProviderName(), sqlSyntaxProviders, Logger);
+ : new DefaultDatabaseFactory(GetDbConnectionString(), GetDbProviderName(), sqlSyntaxProviders, Logger, new TestScopeContextFactory());
// so, using the above code to create a mock IDatabaseFactory if we don't have a real database
// but, that will NOT prevent _appContext from NOT being configured, because it cannot connect
diff --git a/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs b/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs
index bf0db73e6d..f08458d671 100644
--- a/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs
+++ b/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs
@@ -219,7 +219,10 @@ namespace Umbraco.Tests.TestHelpers
var evtMsgs = new TransientMessagesFactory();
ApplicationContext.Current = new ApplicationContext(
//assign the db context
- new DatabaseContext(new DefaultDatabaseFactory(Core.Configuration.GlobalSettings.UmbracoConnectionName, TestObjects.GetDefaultSqlSyntaxProviders(Logger), Logger), Logger),
+ new DatabaseContext(new DefaultDatabaseFactory(
+ Core.Configuration.GlobalSettings.UmbracoConnectionName,
+ TestObjects.GetDefaultSqlSyntaxProviders(Logger),
+ Logger, new TestScopeContextFactory()), Logger),
//assign the service context
TestObjects.GetServiceContext(
Container.GetInstance(),
diff --git a/src/Umbraco.Tests/TestHelpers/TestScopeContext.cs b/src/Umbraco.Tests/TestHelpers/TestScopeContext.cs
new file mode 100644
index 0000000000..cadb3ff84f
--- /dev/null
+++ b/src/Umbraco.Tests/TestHelpers/TestScopeContext.cs
@@ -0,0 +1,27 @@
+using System.Collections.Generic;
+using Umbraco.Core;
+
+namespace Umbraco.Tests.TestHelpers
+{
+ internal class TestScopeContext : IScopeContext
+ {
+ private readonly Dictionary _d = new Dictionary();
+
+ public object GetData(string key)
+ {
+ if (_d.ContainsKey(key)) return _d[key];
+ return null;
+ }
+
+ public void SetData(string key, object data)
+ {
+ _d[key] = data;
+ }
+
+ public void ClearData(string key)
+ {
+ if (_d.ContainsKey(key))
+ _d.Remove(key);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Tests/TestHelpers/TestScopeContextFactory.cs b/src/Umbraco.Tests/TestHelpers/TestScopeContextFactory.cs
new file mode 100644
index 0000000000..ba16271526
--- /dev/null
+++ b/src/Umbraco.Tests/TestHelpers/TestScopeContextFactory.cs
@@ -0,0 +1,20 @@
+using Umbraco.Core;
+
+namespace Umbraco.Tests.TestHelpers
+{
+ internal class TestScopeContextFactory : IScopeContextFactory
+ {
+ private readonly bool _transient = false;
+ private TestScopeContext _ctx;
+
+ public TestScopeContextFactory(bool transient = false)
+ {
+ _transient = transient;
+ }
+
+ public IScopeContext GetContext()
+ {
+ return _transient ? new TestScopeContext() : (_ctx ?? (_ctx = new TestScopeContext()));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj
index b876bddc05..8292be117f 100644
--- a/src/Umbraco.Tests/Umbraco.Tests.csproj
+++ b/src/Umbraco.Tests/Umbraco.Tests.csproj
@@ -187,6 +187,8 @@
+
+
diff --git a/src/Umbraco.Web.UI/Umbraco/Views/AuthorizeUpgrade.cshtml b/src/Umbraco.Web.UI/Umbraco/Views/AuthorizeUpgrade.cshtml
index 8142cf98f2..9481a6f932 100644
--- a/src/Umbraco.Web.UI/Umbraco/Views/AuthorizeUpgrade.cshtml
+++ b/src/Umbraco.Web.UI/Umbraco/Views/AuthorizeUpgrade.cshtml
@@ -64,7 +64,7 @@