Fixes issue with ThreadStatic db
Uses IScopeContext which wraps either HttpContext or CallContext which is created/injected via IOC factory.
This commit is contained in:
25
src/Umbraco.Core/CallContextScope.cs
Normal file
25
src/Umbraco.Core/CallContextScope.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A place to get/retrieve data in a current context (i.e. http, thread, etc...)
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
16
src/Umbraco.Core/DefaultScopeContextFactory.cs
Normal file
16
src/Umbraco.Core/DefaultScopeContextFactory.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System.Web;
|
||||
using Umbraco.Core.Persistence;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Default scope context factory
|
||||
/// </summary>
|
||||
internal class DefaultScopeContextFactory : IScopeContextFactory
|
||||
{
|
||||
public IScopeContext GetContext()
|
||||
{
|
||||
return HttpContext.Current == null ? (IScopeContext)new CallContextScope() : new HttpContextScope();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,8 @@ namespace Umbraco.Core.DependencyInjection
|
||||
container.Register<ISqlSyntaxProvider, SqlCeSyntaxProvider>("SqlCeSyntaxProvider");
|
||||
container.Register<ISqlSyntaxProvider, SqlServerSyntaxProvider>("SqlServerSyntaxProvider");
|
||||
|
||||
container.RegisterSingleton<IScopeContextFactory, DefaultScopeContextFactory>();
|
||||
|
||||
// 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
|
||||
|
||||
25
src/Umbraco.Core/HttpContextScope.cs
Normal file
25
src/Umbraco.Core/HttpContextScope.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System.Web;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A place to get/retrieve data in a current context (i.e. http, thread, etc...)
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
12
src/Umbraco.Core/IScopeContext.cs
Normal file
12
src/Umbraco.Core/IScopeContext.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A place to get/retrieve data in a current context (i.e. http, thread, etc...)
|
||||
/// </summary>
|
||||
internal interface IScopeContext
|
||||
{
|
||||
object GetData(string key);
|
||||
void SetData(string key, object data);
|
||||
void ClearData(string key);
|
||||
}
|
||||
}
|
||||
10
src/Umbraco.Core/IScopeContextFactory.cs
Normal file
10
src/Umbraco.Core/IScopeContextFactory.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets an IScopedContext
|
||||
/// </summary>
|
||||
internal interface IScopeContextFactory
|
||||
{
|
||||
IScopeContext GetContext();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
/// </remarks>
|
||||
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<UmbracoDatabase> _nonHttpInstance;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DefaultDatabaseFactory"/> with the default connection, and a logger.
|
||||
/// </summary>
|
||||
/// <param name="sqlSyntaxProviders">The collection of available sql syntax providers.</param>
|
||||
/// <param name="logger">A logger.</param>
|
||||
/// <param name="scopeContextFactory"></param>
|
||||
/// <remarks>Used by LightInject.</remarks>
|
||||
public DefaultDatabaseFactory(IEnumerable<ISqlSyntaxProvider> sqlSyntaxProviders, ILogger logger)
|
||||
: this(GlobalSettings.UmbracoConnectionName, sqlSyntaxProviders, logger)
|
||||
{
|
||||
public DefaultDatabaseFactory(IEnumerable<ISqlSyntaxProvider> 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
|
||||
/// <param name="connectionStringName">The name of the connection string in web.config.</param>
|
||||
/// <param name="sqlSyntaxProviders">The collection of available sql syntax providers.</param>
|
||||
/// <param name="logger">A logger</param>
|
||||
/// <param name="scopeContextFactory"></param>
|
||||
/// <remarks>Used by the other ctor and in tests.</remarks>
|
||||
public DefaultDatabaseFactory(string connectionStringName, IEnumerable<ISqlSyntaxProvider> sqlSyntaxProviders, ILogger logger)
|
||||
{
|
||||
public DefaultDatabaseFactory(string connectionStringName, IEnumerable<ISqlSyntaxProvider> 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<DefaultDatabaseFactory>("Created!");
|
||||
|
||||
var settings = ConfigurationManager.ConnectionStrings[connectionStringName];
|
||||
if (settings == null)
|
||||
@@ -97,61 +99,73 @@ namespace Umbraco.Core.Persistence
|
||||
/// </summary>
|
||||
/// <param name="connectionString">The database connection string.</param>
|
||||
/// <param name="providerName">The name of the database provider.</param>
|
||||
/// <param name="sqlSyntaxProviders">The collection of available sql syntax providers.</param>
|
||||
/// <param name="sqlSyntaxProviders">The collection of available sql syntax providers.</param>
|
||||
/// <param name="logger">A logger.</param>
|
||||
/// <param name="scopeContextFactory"></param>
|
||||
/// <remarks>Used in tests.</remarks>
|
||||
public DefaultDatabaseFactory(string connectionString, string providerName, IEnumerable<ISqlSyntaxProvider> sqlSyntaxProviders, ILogger logger)
|
||||
{
|
||||
public DefaultDatabaseFactory(string connectionString, string providerName, IEnumerable<ISqlSyntaxProvider> 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<DefaultDatabaseFactory>("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<DefaultDatabaseFactory>("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>(() => (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<DefaultDatabaseFactory>("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.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ namespace Umbraco.Core.Persistence.UnitOfWork
|
||||
/// <see cref="DefaultDatabaseFactory"/> with the default connection name, and default sql syntax providers.</para>
|
||||
/// </remarks>
|
||||
internal NPocoUnitOfWorkProvider(ILogger logger)
|
||||
: this(new DefaultDatabaseFactory(GlobalSettings.UmbracoConnectionName, GetDefaultSqlSyntaxProviders(logger), logger))
|
||||
: this(new DefaultDatabaseFactory(GlobalSettings.UmbracoConnectionName, GetDefaultSqlSyntaxProviders(logger), logger, new DefaultScopeContextFactory()))
|
||||
{ }
|
||||
|
||||
// this should NOT be here, all tests should supply the appropriate providers,
|
||||
|
||||
@@ -377,10 +377,15 @@
|
||||
<Compile Include="Models\PublishedContent\PublishedContentWithKeyWrapped.cs" />
|
||||
<Compile Include="Models\Rdbms\AccessDto.cs" />
|
||||
<Compile Include="ObjectResolution\ContainerSingleObjectResolver.cs" />
|
||||
<Compile Include="CallContextScope.cs" />
|
||||
<Compile Include="Persistence\Constants-DbProviderNames.cs" />
|
||||
<Compile Include="DefaultScopeContextFactory.cs" />
|
||||
<Compile Include="Persistence\FaultHandling\RetryDbConnection.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="HttpContextScope.cs" />
|
||||
<Compile Include="IScopeContext.cs" />
|
||||
<Compile Include="IScopeContextFactory.cs" />
|
||||
<Compile Include="Persistence\IUmbracoDatabaseConfig.cs" />
|
||||
<Compile Include="Persistence\Mappers\AuditItemMapper.cs" />
|
||||
<Compile Include="Persistence\Mappers\IMappingResolver.cs" />
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Umbraco.Tests.Persistence
|
||||
_sqlCeSyntaxProvider = new SqlCeSyntaxProvider();
|
||||
_sqlSyntaxProviders = new[] { (ISqlSyntaxProvider) _sqlCeSyntaxProvider };
|
||||
_logger = Mock.Of<ILogger>();
|
||||
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
|
||||
|
||||
@@ -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<IDatabaseFactory>(() => null)) };
|
||||
var factory = new DefaultDatabaseFactory(connectionString, providerName, sqlSyntax, Mock.Of<ILogger>());
|
||||
var factory = new DefaultDatabaseFactory(connectionString, providerName, sqlSyntax, Mock.Of<ILogger>(), 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<IDatabaseFactory>(() => null)) };
|
||||
var factory = new DefaultDatabaseFactory(connectionString, providerName, sqlSyntax, Mock.Of<ILogger>());
|
||||
var factory = new DefaultDatabaseFactory(connectionString, providerName, sqlSyntax, Mock.Of<ILogger>(), new TestScopeContextFactory());
|
||||
var database = factory.GetDatabase();
|
||||
|
||||
//Act
|
||||
|
||||
@@ -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(
|
||||
Core.Configuration.GlobalSettings.UmbracoConnectionName,
|
||||
TestObjects.GetDefaultSqlSyntaxProviders(Logger),
|
||||
Logger,
|
||||
new TestScopeContextFactory());
|
||||
var provider = new NPocoUnitOfWorkProvider(databaseFactory);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
var contentType = ServiceContext.ContentTypeService.GetContentType("umbTextpage");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -218,7 +218,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<RepositoryFactory>(),
|
||||
|
||||
27
src/Umbraco.Tests/TestHelpers/TestScopeContext.cs
Normal file
27
src/Umbraco.Tests/TestHelpers/TestScopeContext.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Tests.TestHelpers
|
||||
{
|
||||
internal class TestScopeContext : IScopeContext
|
||||
{
|
||||
private readonly Dictionary<string, object> _d = new Dictionary<string, object>();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
20
src/Umbraco.Tests/TestHelpers/TestScopeContextFactory.cs
Normal file
20
src/Umbraco.Tests/TestHelpers/TestScopeContextFactory.cs
Normal file
@@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -187,6 +187,8 @@
|
||||
<Compile Include="Persistence\Migrations\MigrationStartupHandlerTests.cs" />
|
||||
<Compile Include="TestHelpers\TestObjects-Mocks.cs" />
|
||||
<Compile Include="TestHelpers\TestObjects.cs" />
|
||||
<Compile Include="TestHelpers\TestScopeContext.cs" />
|
||||
<Compile Include="TestHelpers\TestScopeContextFactory.cs" />
|
||||
<Compile Include="Web\AngularIntegration\AngularAntiForgeryTests.cs" />
|
||||
<Compile Include="Web\AngularIntegration\ContentModelSerializationTests.cs" />
|
||||
<Compile Include="Web\AngularIntegration\JsInitializationTests.cs" />
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
// partialView
|
||||
@@ -0,0 +1 @@
|
||||
// partialView
|
||||
1
src/Umbraco.Tests/Views/Partials/test-path-1.cshtml
Normal file
1
src/Umbraco.Tests/Views/Partials/test-path-1.cshtml
Normal file
@@ -0,0 +1 @@
|
||||
// partialView
|
||||
1
src/Umbraco.Tests/css/path-2/test-path-2.css
Normal file
1
src/Umbraco.Tests/css/path-2/test-path-2.css
Normal file
@@ -0,0 +1 @@
|
||||
body { color:#000; } .bold {font-weight:bold;}
|
||||
1
src/Umbraco.Tests/css/path-2/test-path-3.css
Normal file
1
src/Umbraco.Tests/css/path-2/test-path-3.css
Normal file
@@ -0,0 +1 @@
|
||||
body { color:#000; } .bold {font-weight:bold;}
|
||||
1
src/Umbraco.Tests/css/styles-v2.css
Normal file
1
src/Umbraco.Tests/css/styles-v2.css
Normal file
@@ -0,0 +1 @@
|
||||
body { color:#000; } .bold {font-weight:bold;}
|
||||
1
src/Umbraco.Tests/css/styles.css
Normal file
1
src/Umbraco.Tests/css/styles.css
Normal file
@@ -0,0 +1 @@
|
||||
body {background:#EE7600; color:#FFF;}
|
||||
1
src/Umbraco.Tests/css/test-add.css
Normal file
1
src/Umbraco.Tests/css/test-add.css
Normal file
@@ -0,0 +1 @@
|
||||
body { color:#000; } .bold {font-weight:bold;}
|
||||
1
src/Umbraco.Tests/css/test-path-1.css
Normal file
1
src/Umbraco.Tests/css/test-path-1.css
Normal file
@@ -0,0 +1 @@
|
||||
body { color:#000; } .bold {font-weight:bold;}
|
||||
1
src/Umbraco.Tests/css/test-update.css
Normal file
1
src/Umbraco.Tests/css/test-update.css
Normal file
@@ -0,0 +1 @@
|
||||
body { color:#000; } .bold {font-weight:bold;}
|
||||
1
src/Umbraco.Tests/scripts/moved/test-move-script.js
Normal file
1
src/Umbraco.Tests/scripts/moved/test-move-script.js
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference name="MicrosoftAjax.js"/>
|
||||
1
src/Umbraco.Tests/scripts/path-2/test-path-2.js
Normal file
1
src/Umbraco.Tests/scripts/path-2/test-path-2.js
Normal file
@@ -0,0 +1 @@
|
||||
// script
|
||||
1
src/Umbraco.Tests/scripts/path-2/test-path-3.js
Normal file
1
src/Umbraco.Tests/scripts/path-2/test-path-3.js
Normal file
@@ -0,0 +1 @@
|
||||
// script
|
||||
1
src/Umbraco.Tests/scripts/test-add-script.js
Normal file
1
src/Umbraco.Tests/scripts/test-add-script.js
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference name="MicrosoftAjax.js"/>
|
||||
1
src/Umbraco.Tests/scripts/test-path-1.js
Normal file
1
src/Umbraco.Tests/scripts/test-path-1.js
Normal file
@@ -0,0 +1 @@
|
||||
// script
|
||||
1
src/Umbraco.Tests/scripts/test-script.js
Normal file
1
src/Umbraco.Tests/scripts/test-script.js
Normal file
@@ -0,0 +1 @@
|
||||
Umbraco.Sys.registerNamespace("Umbraco.Utils");
|
||||
1
src/Umbraco.Tests/scripts/test-script1.js
Normal file
1
src/Umbraco.Tests/scripts/test-script1.js
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference name="MicrosoftAjax.js"/>
|
||||
1
src/Umbraco.Tests/scripts/test-script2.js
Normal file
1
src/Umbraco.Tests/scripts/test-script2.js
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference name="MicrosoftAjax.js"/>
|
||||
1
src/Umbraco.Tests/scripts/test-script3.js
Normal file
1
src/Umbraco.Tests/scripts/test-script3.js
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference name="MicrosoftAjax.js"/>
|
||||
1
src/Umbraco.Tests/scripts/test-updated-script.js
Normal file
1
src/Umbraco.Tests/scripts/test-updated-script.js
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference name="MicrosoftAjax-Updated.js"/>
|
||||
Reference in New Issue
Block a user