diff --git a/README.md b/README.md
index 3e9be6cb5f..1d42543eb3 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
Umbraco CMS
===========
-The friendliest, most flexible and fastest growing ASP.NET CMS used by more than 350,000 websites worldwide: [https://umbraco.com](https://umbraco.com)
+The friendliest, most flexible and fastest growing ASP.NET CMS used by more than 390,000 websites worldwide: [https://umbraco.com](https://umbraco.com)
[](https://vimeo.com/172382998/)
diff --git a/build/NuSpecs/UmbracoCms.Core.nuspec b/build/NuSpecs/UmbracoCms.Core.nuspec
index f442b92551..ce837f7189 100644
--- a/build/NuSpecs/UmbracoCms.Core.nuspec
+++ b/build/NuSpecs/UmbracoCms.Core.nuspec
@@ -15,6 +15,8 @@
en-US
umbraco
+
+
@@ -28,52 +30,51 @@
-
-
+
-
-
-
-
-
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -104,4 +105,4 @@
-
\ No newline at end of file
+
diff --git a/build/NuSpecs/UmbracoCms.nuspec b/build/NuSpecs/UmbracoCms.nuspec
index 41d47df7e9..4a587e8a07 100644
--- a/build/NuSpecs/UmbracoCms.nuspec
+++ b/build/NuSpecs/UmbracoCms.nuspec
@@ -16,9 +16,10 @@
umbraco
-
+
+
@@ -44,6 +45,8 @@
+
+
diff --git a/build/NuSpecs/tools/cache.config.install.xdt b/build/NuSpecs/tools/cache.config.install.xdt
new file mode 100644
index 0000000000..746e3c3298
--- /dev/null
+++ b/build/NuSpecs/tools/cache.config.install.xdt
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build/NuSpecs/tools/install.core.ps1 b/build/NuSpecs/tools/install.core.ps1
index c4f213ba01..e2230e0c32 100644
--- a/build/NuSpecs/tools/install.core.ps1
+++ b/build/NuSpecs/tools/install.core.ps1
@@ -71,6 +71,7 @@ if ($project) {
if(Test-Path $umbracoBinFolder\ImageProcessor.dll) { Remove-Item $umbracoBinFolder\ImageProcessor.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\ImageProcessor.Web.dll) { Remove-Item $umbracoBinFolder\ImageProcessor.Web.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Lucene.Net.dll) { Remove-Item $umbracoBinFolder\Lucene.Net.dll -Force -Confirm:$false }
+ if(Test-Path $umbracoBinFolder\Microsoft.IO.RecyclableMemoryStream.dll) { Remove-Item $umbracoBinFolder\Microsoft.IO.RecyclableMemoryStream.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.AspNet.Identity.Core.dll) { Remove-Item $umbracoBinFolder\Microsoft.AspNet.Identity.Core.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.AspNet.Identity.Owin.dll) { Remove-Item $umbracoBinFolder\Microsoft.AspNet.Identity.Owin.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.CodeAnalysis.CSharp.dll) { Remove-Item $umbracoBinFolder\Microsoft.CodeAnalysis.CSharp.dll -Force -Confirm:$false }
diff --git a/build/NuSpecs/tools/processing.config.install.xdt b/build/NuSpecs/tools/processing.config.install.xdt
new file mode 100644
index 0000000000..0bef321533
--- /dev/null
+++ b/build/NuSpecs/tools/processing.config.install.xdt
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/build/UmbracoVersion.txt b/build/UmbracoVersion.txt
index df03fe8381..a5c5d3f363 100644
--- a/build/UmbracoVersion.txt
+++ b/build/UmbracoVersion.txt
@@ -1,2 +1,3 @@
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
-7.5.5
\ No newline at end of file
+7.6.0
+alpha068
diff --git a/src/SQLCE4Umbraco/SqlCE4Umbraco.csproj b/src/SQLCE4Umbraco/SqlCE4Umbraco.csproj
index 86796e1dd7..2904410748 100644
--- a/src/SQLCE4Umbraco/SqlCE4Umbraco.csproj
+++ b/src/SQLCE4Umbraco/SqlCE4Umbraco.csproj
@@ -1,5 +1,5 @@
-
+
Debug
AnyCPU
@@ -10,7 +10,7 @@
Properties
SQLCE4Umbraco
SQLCE4Umbraco
- v4.5
+ v4.6.2
512
@@ -49,13 +49,9 @@
..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll
- False
- False
..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll
- False
- False
diff --git a/src/SQLCE4Umbraco/SqlCeApplicationBlock.cs b/src/SQLCE4Umbraco/SqlCeApplicationBlock.cs
index fd778bbfb3..2dd0f26e90 100644
--- a/src/SQLCE4Umbraco/SqlCeApplicationBlock.cs
+++ b/src/SQLCE4Umbraco/SqlCeApplicationBlock.cs
@@ -240,7 +240,7 @@ namespace SqlCE4Umbraco
{
var cmd = trx == null ? new SqlCeCommand(commandText, conn) : new SqlCeCommand(commandText, conn, trx);
AttachParameters(cmd, commandParameters);
- return cmd.ExecuteReader(CommandBehavior.CloseConnection);
+ return cmd.ExecuteReader();
}
catch
{
diff --git a/src/SQLCE4Umbraco/app.config b/src/SQLCE4Umbraco/app.config
index 1f5a6442ad..6d9f461c6f 100644
--- a/src/SQLCE4Umbraco/app.config
+++ b/src/SQLCE4Umbraco/app.config
@@ -4,7 +4,7 @@
-
+
@@ -32,4 +32,4 @@
-
\ No newline at end of file
+
diff --git a/src/SolutionInfo.cs b/src/SolutionInfo.cs
index f6a14611df..05460ef463 100644
--- a/src/SolutionInfo.cs
+++ b/src/SolutionInfo.cs
@@ -2,7 +2,7 @@
using System.Resources;
[assembly: AssemblyCompany("Umbraco")]
-[assembly: AssemblyCopyright("Copyright © Umbraco 2016")]
+[assembly: AssemblyCopyright("Copyright © Umbraco 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -12,4 +12,4 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.6.0")]
-[assembly: AssemblyInformationalVersion("7.6.0-alpha032")]
\ No newline at end of file
+[assembly: AssemblyInformationalVersion("7.6.0-alpha068")]
\ No newline at end of file
diff --git a/src/Umbraco.Core/ApplicationContext.cs b/src/Umbraco.Core/ApplicationContext.cs
index e47ef04650..5b2caf409f 100644
--- a/src/Umbraco.Core/ApplicationContext.cs
+++ b/src/Umbraco.Core/ApplicationContext.cs
@@ -7,6 +7,7 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.ObjectResolution;
using Umbraco.Core.Profiling;
+using Umbraco.Core.Scoping;
using Umbraco.Core.Services;
using Umbraco.Core.Sync;
@@ -162,6 +163,9 @@ namespace Umbraco.Core
///
public static ApplicationContext Current { get; internal set; }
+ // fixme
+ internal IScopeProvider ScopeProvider { get { return _databaseContext == null ? null : _databaseContext.ScopeProvider; } }
+
///
/// Returns the application wide cache accessor
///
@@ -296,7 +300,7 @@ namespace Umbraco.Core
// if we have a db context available, if we don't then we are not installed anyways
if (DatabaseContext.IsDatabaseConfigured && DatabaseContext.CanConnect)
{
- var found = Services.MigrationEntryService.FindEntry(GlobalSettings.UmbracoMigrationName, UmbracoVersion.GetSemanticVersion());
+ var found = Services.MigrationEntryService.FindEntry(Constants.System.UmbracoMigrationName, UmbracoVersion.GetSemanticVersion());
if (found == null)
{
//we haven't executed this migration in this environment, so even though the config versions match,
@@ -418,10 +422,17 @@ namespace Umbraco.Core
this.ApplicationCache = null;
if (_databaseContext != null) //need to check the internal field here
{
+ if (_databaseContext.ScopeProvider.AmbientScope != null)
+ {
+ var scope = _databaseContext.ScopeProvider.AmbientScope;
+ scope.Dispose();
+ }
+ /*
if (DatabaseContext.IsDatabaseConfigured && DatabaseContext.Database != null)
{
DatabaseContext.Database.Dispose();
- }
+ }
+ */
}
this.DatabaseContext = null;
this.Services = null;
diff --git a/src/Umbraco.Core/BindingRedirects.cs b/src/Umbraco.Core/BindingRedirects.cs
new file mode 100644
index 0000000000..2ee54a369b
--- /dev/null
+++ b/src/Umbraco.Core/BindingRedirects.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Reflection;
+using System.Text.RegularExpressions;
+using System.Web;
+using Umbraco.Core;
+
+namespace Umbraco.Core
+{
+ ///
+ /// Manages any assembly binding redirects that cannot be done via config
+ ///
+ internal class BindingRedirects
+ {
+ public static void Initialize()
+ {
+ // this only gets called when an assembly can't be resolved
+ AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
+ }
+
+ private static readonly Regex Log4NetAssemblyPattern = new Regex("log4net, Version=([\\d\\.]+?), Culture=neutral, PublicKeyToken=null", RegexOptions.Compiled);
+ private const string Log4NetReplacement = "log4net, Version=1.2.15.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a";
+
+ ///
+ /// This is used to do an assembly binding redirect via code - normally required due to signature changes in assemblies
+ ///
+ ///
+ ///
+ ///
+ private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
+ {
+ //log4net:
+ // Use regex to match and replace
+ if (Log4NetAssemblyPattern.IsMatch(args.Name) && args.Name != Log4NetReplacement)
+ {
+ return Assembly.Load(Log4NetAssemblyPattern.Replace(args.Name, Log4NetReplacement));
+ }
+
+ //AutoMapper:
+ // ensure the assembly is indeed AutoMapper and that the PublicKeyToken is null before trying to Load again
+ // do NOT just replace this with 'return Assembly', as it will cause an infinite loop -> stackoverflow
+ if (args.Name.StartsWith("AutoMapper") && args.Name.EndsWith("PublicKeyToken=null"))
+ return Assembly.Load(args.Name.Replace(", PublicKeyToken=null", ", PublicKeyToken=be96cd2c38ef1005"));
+
+ return null;
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Cache/CacheKeys.cs b/src/Umbraco.Core/Cache/CacheKeys.cs
index 0c1a202b66..3b9ee9c63a 100644
--- a/src/Umbraco.Core/Cache/CacheKeys.cs
+++ b/src/Umbraco.Core/Cache/CacheKeys.cs
@@ -64,7 +64,8 @@ namespace Umbraco.Core.Cache
[UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")]
public const string ContentTypePropertiesCacheKey = "ContentType_PropertyTypes_Content:";
- [UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")]
+ [Obsolete("No longer used and will be removed in v8")]
+ [EditorBrowsable(EditorBrowsableState.Never)]
public const string PropertyTypeCacheKey = "UmbracoPropertyTypeCache";
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
diff --git a/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs
index 1f51fc3ccc..fc98473c4c 100644
--- a/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs
+++ b/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs
@@ -1,23 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using Umbraco.Core.Logging;
using Umbraco.Core.Models.EntityBase;
+using Umbraco.Core.Scoping;
namespace Umbraco.Core.Cache
{
///
- /// The default cache policy for retrieving a single entity
+ /// Represents the default cache policy.
///
- ///
- ///
+ /// The type of the entity.
+ /// The type of the identifier.
///
- /// This cache policy uses sliding expiration and caches instances for 5 minutes. However if allow zero count is true, then we use the
- /// default policy with no expiry.
+ /// The default cache policy caches entities with a 5 minutes sliding expiration.
+ /// Each entity is cached individually.
+ /// If options.GetAllCacheAllowZeroCount then a 'zero-count' array is cached when GetAll finds nothing.
+ /// If options.GetAllCacheValidateCount then we check against the db when getting many entities.
///
internal class DefaultRepositoryCachePolicy : RepositoryCachePolicyBase
where TEntity : class, IAggregateRoot
{
+ private static readonly TEntity[] EmptyEntities = new TEntity[0]; // const
private readonly RepositoryCachePolicyOptions _options;
public DefaultRepositoryCachePolicy(IRuntimeCacheProvider cache, RepositoryCachePolicyOptions options)
@@ -27,242 +30,223 @@ namespace Umbraco.Core.Cache
_options = options;
}
- protected string GetCacheIdKey(object id)
+ public override IRepositoryCachePolicy Scoped(IRuntimeCacheProvider runtimeCache, IScope scope)
{
- if (id == null) throw new ArgumentNullException("id");
-
- return string.Format("{0}{1}", GetCacheTypeKey(), id);
+ return new ScopedRepositoryCachePolicy(this, runtimeCache, scope);
}
- protected string GetCacheTypeKey()
+ protected string GetEntityCacheKey(object id)
+ {
+ if (id == null) throw new ArgumentNullException("id");
+ return GetEntityTypeCacheKey() + id;
+ }
+
+ protected string GetEntityTypeCacheKey()
{
return string.Format("uRepo_{0}_", typeof(TEntity).Name);
}
- public override void CreateOrUpdate(TEntity entity, Action persistMethod)
+ protected virtual void InsertEntity(string cacheKey, TEntity entity)
+ {
+ Cache.InsertCacheItem(cacheKey, () => entity, TimeSpan.FromMinutes(5), true);
+ }
+
+ protected virtual void InsertEntities(TId[] ids, TEntity[] entities)
+ {
+ if (ids.Length == 0 && entities.Length == 0 && _options.GetAllCacheAllowZeroCount)
+ {
+ // getting all of them, and finding nothing.
+ // if we can cache a zero count, cache an empty array,
+ // for as long as the cache is not cleared (no expiration)
+ Cache.InsertCacheItem(GetEntityTypeCacheKey(), () => EmptyEntities);
+ }
+ else
+ {
+ // individually cache each item
+ foreach (var entity in entities)
+ {
+ var capture = entity;
+ Cache.InsertCacheItem(GetEntityCacheKey(entity.Id), () => capture, TimeSpan.FromMinutes(5), true);
+ }
+ }
+ }
+
+ ///
+ public override void Create(TEntity entity, Action persistNew)
{
if (entity == null) throw new ArgumentNullException("entity");
- if (persistMethod == null) throw new ArgumentNullException("persistMethod");
try
{
- persistMethod(entity);
+ persistNew(entity);
- //set the disposal action
- SetCacheAction(() =>
+ // just to be safe, we cannot cache an item without an identity
+ if (entity.HasIdentity)
{
- //just to be safe, we cannot cache an item without an identity
- if (entity.HasIdentity)
- {
- Cache.InsertCacheItem(GetCacheIdKey(entity.Id), () => entity,
- timeout: TimeSpan.FromMinutes(5),
- isSliding: true);
- }
-
- //If there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
- Cache.ClearCacheItem(GetCacheTypeKey());
- });
-
+ Cache.InsertCacheItem(GetEntityCacheKey(entity.Id), () => entity, TimeSpan.FromMinutes(5), true);
+ }
+
+ // if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
+ Cache.ClearCacheItem(GetEntityTypeCacheKey());
}
catch
{
- //set the disposal action
- SetCacheAction(() =>
- {
- //if an exception is thrown we need to remove the entry from cache, this is ONLY a work around because of the way
- // that we cache entities: http://issues.umbraco.org/issue/U4-4259
- Cache.ClearCacheItem(GetCacheIdKey(entity.Id));
+ // if an exception is thrown we need to remove the entry from cache,
+ // this is ONLY a work around because of the way
+ // that we cache entities: http://issues.umbraco.org/issue/U4-4259
+ Cache.ClearCacheItem(GetEntityCacheKey(entity.Id));
+
+ // if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
+ Cache.ClearCacheItem(GetEntityTypeCacheKey());
- //If there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
- Cache.ClearCacheItem(GetCacheTypeKey());
- });
-
throw;
}
}
- public override void Remove(TEntity entity, Action persistMethod)
+ ///
+ public override void Update(TEntity entity, Action persistUpdated)
{
if (entity == null) throw new ArgumentNullException("entity");
- if (persistMethod == null) throw new ArgumentNullException("persistMethod");
try
{
- persistMethod(entity);
- }
- finally
- {
- //set the disposal action
- var cacheKey = GetCacheIdKey(entity.Id);
- SetCacheAction(() =>
+ persistUpdated(entity);
+
+ // just to be safe, we cannot cache an item without an identity
+ if (entity.HasIdentity)
{
- Cache.ClearCacheItem(cacheKey);
- //If there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
- Cache.ClearCacheItem(GetCacheTypeKey());
- });
+ Cache.InsertCacheItem(GetEntityCacheKey(entity.Id), () => entity, TimeSpan.FromMinutes(5), true);
+ }
+
+ // if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
+ Cache.ClearCacheItem(GetEntityTypeCacheKey());
+ }
+ catch
+ {
+ // if an exception is thrown we need to remove the entry from cache,
+ // this is ONLY a work around because of the way
+ // that we cache entities: http://issues.umbraco.org/issue/U4-4259
+ Cache.ClearCacheItem(GetEntityCacheKey(entity.Id));
+
+ // if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
+ Cache.ClearCacheItem(GetEntityTypeCacheKey());
+
+ throw;
}
}
- public override TEntity Get(TId id, Func getFromRepo)
+ ///
+ public override void Delete(TEntity entity, Action persistDeleted)
{
- if (getFromRepo == null) throw new ArgumentNullException("getFromRepo");
+ if (entity == null) throw new ArgumentNullException("entity");
- var cacheKey = GetCacheIdKey(id);
+ try
+ {
+ persistDeleted(entity);
+ }
+ finally
+ {
+ // whatever happens, clear the cache
+ var cacheKey = GetEntityCacheKey(entity.Id);
+ Cache.ClearCacheItem(cacheKey);
+ // if there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
+ Cache.ClearCacheItem(GetEntityTypeCacheKey());
+ }
+ }
+
+ ///
+ public override TEntity Get(TId id, Func performGet, Func> performGetAll)
+ {
+ var cacheKey = GetEntityCacheKey(id);
var fromCache = Cache.GetCacheItem(cacheKey);
+
+ // if found in cache then return else fetch and cache
if (fromCache != null)
return fromCache;
-
- var entity = getFromRepo(id);
+ var entity = performGet(id);
- //set the disposal action
- SetCacheAction(cacheKey, entity);
+ if (entity != null && entity.HasIdentity)
+ InsertEntity(cacheKey, entity);
return entity;
}
- public override TEntity Get(TId id)
+ ///
+ public override TEntity GetCached(TId id)
{
- var cacheKey = GetCacheIdKey(id);
+ var cacheKey = GetEntityCacheKey(id);
return Cache.GetCacheItem(cacheKey);
}
- public override bool Exists(TId id, Func getFromRepo)
+ ///
+ public override bool Exists(TId id, Func performExists, Func> performGetAll)
{
- if (getFromRepo == null) throw new ArgumentNullException("getFromRepo");
-
- var cacheKey = GetCacheIdKey(id);
+ // if found in cache the return else check
+ var cacheKey = GetEntityCacheKey(id);
var fromCache = Cache.GetCacheItem(cacheKey);
- return fromCache != null || getFromRepo(id);
+ return fromCache != null || performExists(id);
}
- public override TEntity[] GetAll(TId[] ids, Func> getFromRepo)
+ ///
+ public override TEntity[] GetAll(TId[] ids, Func> performGetAll)
{
- if (getFromRepo == null) throw new ArgumentNullException("getFromRepo");
-
- if (ids.Any())
+ if (ids.Length > 0)
{
- var entities = ids.Select(Get).ToArray();
- if (ids.Length.Equals(entities.Length) && entities.Any(x => x == null) == false)
- return entities;
+ // try to get each entity from the cache
+ // if we can find all of them, return
+ var entities = ids.Select(GetCached).WhereNotNull().ToArray();
+ if (ids.Length.Equals(entities.Length))
+ return entities; // no need for null checks, we are not caching nulls
}
else
{
- var allEntities = GetAllFromCache();
- if (allEntities.Any())
+ // get everything we have
+ var entities = Cache.GetCacheItemsByKeySearch(GetEntityTypeCacheKey())
+ .ToArray(); // no need for null checks, we are not caching nulls
+
+ if (entities.Length > 0)
{
+ // if some of them were in the cache...
if (_options.GetAllCacheValidateCount)
{
- //Get count of all entities of current type (TEntity) to ensure cached result is correct
+ // need to validate the count, get the actual count and return if ok
var totalCount = _options.PerformCount();
- if (allEntities.Length == totalCount)
- return allEntities;
+ if (entities.Length == totalCount)
+ return entities;
}
else
{
- return allEntities;
+ // no need to validate, just return what we have and assume it's all there is
+ return entities;
}
}
else if (_options.GetAllCacheAllowZeroCount)
{
- //if the repository allows caching a zero count, then check the zero count cache
- if (HasZeroCountCache())
- {
- //there is a zero count cache so return an empty list
- return new TEntity[] {};
- }
+ // if none of them were in the cache
+ // and we allow zero count - check for the special (empty) entry
+ var empty = Cache.GetCacheItem(GetEntityTypeCacheKey());
+ if (empty != null) return empty;
}
}
- //we need to do the lookup from the repo
- var entityCollection = getFromRepo(ids)
- //ensure we don't include any null refs in the returned collection!
- .WhereNotNull()
+ // cache failed, get from repo and cache
+ var repoEntities = performGetAll(ids)
+ .WhereNotNull() // exclude nulls!
+ .Where(x => x.HasIdentity) // be safe, though would be weird...
.ToArray();
- //set the disposal action
- SetCacheAction(ids, entityCollection);
+ // note: if empty & allow zero count, will cache a special (empty) entry
+ InsertEntities(ids, repoEntities);
- return entityCollection;
+ return repoEntities;
}
- ///
- /// Looks up the zero count cache, must return null if it doesn't exist
- ///
- ///
- protected bool HasZeroCountCache()
+ ///
+ public override void ClearAll()
{
- var zeroCount = Cache.GetCacheItem(GetCacheTypeKey());
- return (zeroCount != null && zeroCount.Any() == false);
+ // fixme the cache should NOT contain anything else so we can clean all, can't we?
+ Cache.ClearAllCache();
+ //Cache.ClearCacheByKeySearch(GetEntityTypeCacheKey());
}
-
- ///
- /// Performs the lookup for all entities of this type from the cache
- ///
- ///
- protected TEntity[] GetAllFromCache()
- {
- var allEntities = Cache.GetCacheItemsByKeySearch(GetCacheTypeKey())
- .WhereNotNull()
- .ToArray();
- return allEntities.Any() ? allEntities : new TEntity[] {};
- }
-
- ///
- /// Sets the action to execute on disposal for a single entity
- ///
- ///
- ///
- protected virtual void SetCacheAction(string cacheKey, TEntity entity)
- {
- if (entity == null) return;
-
- SetCacheAction(() =>
- {
- //just to be safe, we cannot cache an item without an identity
- if (entity.HasIdentity)
- {
- Cache.InsertCacheItem(cacheKey, () => entity,
- timeout: TimeSpan.FromMinutes(5),
- isSliding: true);
- }
- });
- }
-
- ///
- /// Sets the action to execute on disposal for an entity collection
- ///
- ///
- ///
- protected virtual void SetCacheAction(TId[] ids, TEntity[] entityCollection)
- {
- SetCacheAction(() =>
- {
- //This option cannot execute if we are looking up specific Ids
- if (ids.Any() == false && entityCollection.Length == 0 && _options.GetAllCacheAllowZeroCount)
- {
- //there was nothing returned but we want to cache a zero count result so add an TEntity[] to the cache
- // to signify that there is a zero count cache
- //NOTE: Don't set expiry/sliding for a zero count
- Cache.InsertCacheItem(GetCacheTypeKey(), () => new TEntity[] {});
- }
- else
- {
- //This is the default behavior, we'll individually cache each item so that if/when these items are resolved
- // by id, they are returned from the already existing cache.
- foreach (var entity in entityCollection.WhereNotNull())
- {
- var localCopy = entity;
- //just to be safe, we cannot cache an item without an identity
- if (localCopy.HasIdentity)
- {
- Cache.InsertCacheItem(GetCacheIdKey(entity.Id), () => localCopy,
- timeout: TimeSpan.FromMinutes(5),
- isSliding: true);
- }
- }
- }
- });
- }
-
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicyFactory.cs b/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicyFactory.cs
deleted file mode 100644
index 5c02e41a48..0000000000
--- a/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicyFactory.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using Umbraco.Core.Models.EntityBase;
-
-namespace Umbraco.Core.Cache
-{
- ///
- /// Creates cache policies
- ///
- ///
- ///
- internal class DefaultRepositoryCachePolicyFactory : IRepositoryCachePolicyFactory
- where TEntity : class, IAggregateRoot
- {
- private readonly IRuntimeCacheProvider _runtimeCache;
- private readonly RepositoryCachePolicyOptions _options;
-
- public DefaultRepositoryCachePolicyFactory(IRuntimeCacheProvider runtimeCache, RepositoryCachePolicyOptions options)
- {
- _runtimeCache = runtimeCache;
- _options = options;
- }
-
- public virtual IRepositoryCachePolicy CreatePolicy()
- {
- return new DefaultRepositoryCachePolicy(_runtimeCache, _options);
- }
- }
-}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicy.cs
index 9b37d1861f..41c0249877 100644
--- a/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicy.cs
+++ b/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicy.cs
@@ -3,227 +3,178 @@ using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Collections;
using Umbraco.Core.Models.EntityBase;
+using Umbraco.Core.Scoping;
namespace Umbraco.Core.Cache
{
///
- /// A caching policy that caches an entire dataset as a single collection
+ /// Represents a caching policy that caches the entire entities set as a single collection.
///
- ///
- ///
+ /// The type of the entity.
+ /// The type of the identifier.
+ ///
+ /// Caches the entire set of entities as a single collection.
+ /// Used by Content-, Media- and MemberTypeRepository, DataTypeRepository, DomainRepository,
+ /// LanguageRepository, PublicAccessRepository, TemplateRepository... things that make sense to
+ /// keep as a whole in memory.
+ ///
internal class FullDataSetRepositoryCachePolicy : RepositoryCachePolicyBase
where TEntity : class, IAggregateRoot
{
- private readonly Func _getEntityId;
- private readonly Func> _getAllFromRepo;
+ private readonly Func _entityGetId;
private readonly bool _expires;
- public FullDataSetRepositoryCachePolicy(IRuntimeCacheProvider cache, Func getEntityId, Func> getAllFromRepo, bool expires)
+ public FullDataSetRepositoryCachePolicy(IRuntimeCacheProvider cache, Func entityGetId, bool expires)
: base(cache)
{
- _getEntityId = getEntityId;
- _getAllFromRepo = getAllFromRepo;
+ _entityGetId = entityGetId;
_expires = expires;
}
- private bool? _hasZeroCountCache;
+ public override IRepositoryCachePolicy Scoped(IRuntimeCacheProvider runtimeCache, IScope scope)
+ {
+ return new ScopedRepositoryCachePolicy(this, runtimeCache, scope);
+ }
+ protected static readonly TId[] EmptyIds = new TId[0]; // const
- protected string GetCacheTypeKey()
+ protected string GetEntityTypeCacheKey()
{
return string.Format("uRepo_{0}_", typeof(TEntity).Name);
}
- public override void CreateOrUpdate(TEntity entity, Action persistMethod)
+ protected void InsertEntities(TEntity[] entities)
{
- if (entity == null) throw new ArgumentNullException("entity");
- if (persistMethod == null) throw new ArgumentNullException("persistMethod");
+ // cache is expected to be a deep-cloning cache ie it deep-clones whatever is
+ // IDeepCloneable when it goes in, and out. it also resets dirty properties,
+ // making sure that no 'dirty' entity is cached.
+ //
+ // this policy is caching the entire list of entities. to ensure that entities
+ // are properly deep-clones when cached, it uses a DeepCloneableList. however,
+ // we don't want to deep-clone *each* entity in the list when fetching it from
+ // cache as that would not be efficient for Get(id). so the DeepCloneableList is
+ // set to ListCloneBehavior.CloneOnce ie it will clone *once* when inserting,
+ // and then will *not* clone when retrieving.
- try
+ if (_expires)
{
- persistMethod(entity);
-
- //set the disposal action
- SetCacheAction(() =>
- {
- //Clear all
- Cache.ClearCacheItem(GetCacheTypeKey());
- });
+ Cache.InsertCacheItem(GetEntityTypeCacheKey(), () => new DeepCloneableList(entities), TimeSpan.FromMinutes(5), true);
}
- catch
+ else
{
- //set the disposal action
- SetCacheAction(() =>
- {
- //Clear all
- Cache.ClearCacheItem(GetCacheTypeKey());
- });
- throw;
+ Cache.InsertCacheItem(GetEntityTypeCacheKey(), () => new DeepCloneableList(entities));
}
}
- public override void Remove(TEntity entity, Action persistMethod)
+ ///
+ public override void Create(TEntity entity, Action persistNew)
{
if (entity == null) throw new ArgumentNullException("entity");
- if (persistMethod == null) throw new ArgumentNullException("persistMethod");
try
{
- persistMethod(entity);
+ persistNew(entity);
}
finally
{
- //set the disposal action
- SetCacheAction(() =>
- {
- //Clear all
- Cache.ClearCacheItem(GetCacheTypeKey());
- });
+ ClearAll();
}
}
- public override TEntity Get(TId id, Func getFromRepo)
+ ///
+ public override void Update(TEntity entity, Action persistUpdated)
{
- //Force get all with cache
- var found = GetAll(new TId[] { }, ids => _getAllFromRepo().WhereNotNull());
+ if (entity == null) throw new ArgumentNullException("entity");
- //we don't have anything in cache (this should never happen), just return from the repo
- if (found == null) return getFromRepo(id);
- var entity = found.FirstOrDefault(x => _getEntityId(x).Equals(id));
- if (entity == null) return null;
-
- //We must ensure to deep clone each one out manually since the deep clone list only clones one way
- return (TEntity)entity.DeepClone();
- }
-
- public override TEntity Get(TId id)
- {
- //Force get all with cache
- var found = GetAll(new TId[] { }, ids => _getAllFromRepo().WhereNotNull());
-
- //we don't have anything in cache (this should never happen), just return null
- if (found == null) return null;
- var entity = found.FirstOrDefault(x => _getEntityId(x).Equals(id));
- if (entity == null) return null;
-
- //We must ensure to deep clone each one out manually since the deep clone list only clones one way
- return (TEntity)entity.DeepClone();
- }
-
- public override bool Exists(TId id, Func getFromRepo)
- {
- //Force get all with cache
- var found = GetAll(new TId[] { }, ids => _getAllFromRepo().WhereNotNull());
-
- //we don't have anything in cache (this should never happen), just return from the repo
- return found == null
- ? getFromRepo(id)
- : found.Any(x => _getEntityId(x).Equals(id));
- }
-
- public override TEntity[] GetAll(TId[] ids, Func> getFromRepo)
- {
- //process getting all including setting the cache callback
- var result = PerformGetAll(getFromRepo);
-
- //now that the base result has been calculated, they will all be cached.
- // Now we can just filter by ids if they have been supplied
-
- return (ids.Any()
- ? result.Where(x => ids.Contains(_getEntityId(x))).ToArray()
- : result)
- //We must ensure to deep clone each one out manually since the deep clone list only clones one way
- .Select(x => (TEntity)x.DeepClone())
- .ToArray();
- }
-
- private TEntity[] PerformGetAll(Func> getFromRepo)
- {
- var allEntities = GetAllFromCache();
- if (allEntities.Any())
+ try
{
- return allEntities;
+ persistUpdated(entity);
}
-
- //check the zero count cache
- if (HasZeroCountCache())
+ finally
{
- //there is a zero count cache so return an empty list
- return new TEntity[] { };
+ ClearAll();
}
-
- //we need to do the lookup from the repo
- var entityCollection = getFromRepo(new TId[] { })
- //ensure we don't include any null refs in the returned collection!
- .WhereNotNull()
- .ToArray();
-
- //set the disposal action
- SetCacheAction(entityCollection);
-
- return entityCollection;
}
- ///
- /// For this type of caching policy, we don't cache individual items
- ///
- ///
- ///
- protected void SetCacheAction(string cacheKey, TEntity entity)
+ ///
+ public override void Delete(TEntity entity, Action persistDeleted)
{
- //No-op
- }
+ if (entity == null) throw new ArgumentNullException("entity");
- ///
- /// Sets the action to execute on disposal for an entity collection
- ///
- ///
- protected void SetCacheAction(TEntity[] entityCollection)
- {
- //set the disposal action
- SetCacheAction(() =>
+ try
{
- //We want to cache the result as a single collection
-
- if (_expires)
- {
- Cache.InsertCacheItem(GetCacheTypeKey(), () => new DeepCloneableList(entityCollection),
- timeout: TimeSpan.FromMinutes(5),
- isSliding: true);
- }
- else
- {
- Cache.InsertCacheItem(GetCacheTypeKey(), () => new DeepCloneableList(entityCollection));
- }
- });
+ persistDeleted(entity);
+ }
+ finally
+ {
+ ClearAll();
+ }
}
- ///
- /// Looks up the zero count cache, must return null if it doesn't exist
- ///
- ///
- protected bool HasZeroCountCache()
+ ///
+ public override TEntity Get(TId id, Func performGet, Func> performGetAll)
{
- if (_hasZeroCountCache.HasValue)
- return _hasZeroCountCache.Value;
+ // get all from the cache, then look for the entity
+ var all = GetAllCached(performGetAll);
+ var entity = all.FirstOrDefault(x => _entityGetId(x).Equals(id));
- _hasZeroCountCache = Cache.GetCacheItem>(GetCacheTypeKey()) != null;
- return _hasZeroCountCache.Value;
+ // see note in InsertEntities - what we get here is the original
+ // cached entity, not a clone, so we need to manually ensure it is deep-cloned.
+ return entity == null ? null : (TEntity) entity.DeepClone();
}
- ///
- /// This policy will cache the full data set as a single collection
- ///
- ///
- protected TEntity[] GetAllFromCache()
+ ///
+ public override TEntity GetCached(TId id)
{
- var found = Cache.GetCacheItem>(GetCacheTypeKey());
+ // get all from the cache -- and only the cache, then look for the entity
+ var all = Cache.GetCacheItem>(GetEntityTypeCacheKey());
+ var entity = all == null ? null : all.FirstOrDefault(x => _entityGetId(x).Equals(id));
- //This method will get called before checking for zero count cache, so we'll just set the flag here
- _hasZeroCountCache = found != null;
-
- return found == null ? new TEntity[] { } : found.WhereNotNull().ToArray();
+ // see note in InsertEntities - what we get here is the original
+ // cached entity, not a clone, so we need to manually ensure it is deep-cloned.
+ return entity == null ? null : (TEntity)entity.DeepClone();
}
+ ///
+ public override bool Exists(TId id, Func performExits, Func> performGetAll)
+ {
+ // get all as one set, then look for the entity
+ var all = GetAllCached(performGetAll);
+ return all.Any(x => _entityGetId(x).Equals(id));
+ }
+
+ ///
+ public override TEntity[] GetAll(TId[] ids, Func> performGetAll)
+ {
+ // get all as one set, from cache if possible, else repo
+ var all = GetAllCached(performGetAll);
+
+ // if ids have been specified, filter
+ if (ids.Length > 0) all = all.Where(x => ids.Contains(_entityGetId(x)));
+
+ // and return
+ // see note in SetCacheActionToInsertEntities - what we get here is the original
+ // cached entities, not clones, so we need to manually ensure they are deep-cloned.
+ return all.Select(x => (TEntity) x.DeepClone()).ToArray();
+ }
+
+ // does NOT clone anything, so be nice with the returned values
+ private IEnumerable GetAllCached(Func> performGetAll)
+ {
+ // try the cache first
+ var all = Cache.GetCacheItem>(GetEntityTypeCacheKey());
+ if (all != null) return all.ToArray();
+
+ // else get from repo and cache
+ var entities = performGetAll(EmptyIds).WhereNotNull().ToArray();
+ InsertEntities(entities); // may be an empty array...
+ return entities;
+ }
+
+ ///
+ public override void ClearAll()
+ {
+ Cache.ClearCacheItem(GetEntityTypeCacheKey());
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicyFactory.cs b/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicyFactory.cs
deleted file mode 100644
index e4addcf355..0000000000
--- a/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicyFactory.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Umbraco.Core.Models.EntityBase;
-
-namespace Umbraco.Core.Cache
-{
- ///
- /// Creates cache policies
- ///
- ///
- ///
- internal class FullDataSetRepositoryCachePolicyFactory : IRepositoryCachePolicyFactory
- where TEntity : class, IAggregateRoot
- {
- private readonly IRuntimeCacheProvider _runtimeCache;
- private readonly Func _getEntityId;
- private readonly Func> _getAllFromRepo;
- private readonly bool _expires;
-
- public FullDataSetRepositoryCachePolicyFactory(IRuntimeCacheProvider runtimeCache, Func getEntityId, Func> getAllFromRepo, bool expires)
- {
- _runtimeCache = runtimeCache;
- _getEntityId = getEntityId;
- _getAllFromRepo = getAllFromRepo;
- _expires = expires;
- }
-
- public virtual IRepositoryCachePolicy CreatePolicy()
- {
- return new FullDataSetRepositoryCachePolicy(_runtimeCache, _getEntityId, _getAllFromRepo, _expires);
- }
- }
-}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Cache/IRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/IRepositoryCachePolicy.cs
index 215487c3be..cd37ac1e60 100644
--- a/src/Umbraco.Core/Cache/IRepositoryCachePolicy.cs
+++ b/src/Umbraco.Core/Cache/IRepositoryCachePolicy.cs
@@ -1,18 +1,90 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Models.EntityBase;
+using Umbraco.Core.Scoping;
namespace Umbraco.Core.Cache
{
- internal interface IRepositoryCachePolicy : IDisposable
+ internal interface IRepositoryCachePolicy
where TEntity : class, IAggregateRoot
{
- TEntity Get(TId id, Func getFromRepo);
- TEntity Get(TId id);
- bool Exists(TId id, Func getFromRepo);
-
- void CreateOrUpdate(TEntity entity, Action persistMethod);
- void Remove(TEntity entity, Action persistMethod);
- TEntity[] GetAll(TId[] ids, Func> getFromRepo);
+ // note:
+ // at the moment each repository instance creates its corresponding cache policy instance
+ // we could reduce allocations by using static cache policy instances but then we would need
+ // to modify all methods here to pass the repository and cache eg:
+ //
+ // TEntity Get(TRepository repository, IRuntimeCacheProvider cache, TId id);
+ //
+ // it is not *that* complicated but then RepositoryBase needs to have a TRepository generic
+ // type parameter and it all becomes convoluted - keeping it simple for the time being.
+
+ // fixme explain
+ IRepositoryCachePolicy Scoped(IRuntimeCacheProvider runtimeCache, IScope scope);
+
+ ///
+ /// Gets an entity from the cache, else from the repository.
+ ///
+ /// The identifier.
+ /// The repository PerformGet method.
+ /// The repository PerformGetAll method.
+ /// The entity with the specified identifier, if it exits, else null.
+ /// First considers the cache then the repository.
+ TEntity Get(TId id, Func performGet, Func> performGetAll);
+
+ ///
+ /// Gets an entity from the cache.
+ ///
+ /// The identifier.
+ /// The entity with the specified identifier, if it is in the cache already, else null.
+ /// Does not consider the repository at all.
+ TEntity GetCached(TId id);
+
+ ///
+ /// Gets a value indicating whether an entity with a specified identifier exists.
+ ///
+ /// The identifier.
+ /// The repository PerformExists method.
+ /// The repository PerformGetAll method.
+ /// A value indicating whether an entity with the specified identifier exists.
+ /// First considers the cache then the repository.
+ bool Exists(TId id, Func performExists, Func> performGetAll);
+
+ ///
+ /// Creates an entity.
+ ///
+ /// The entity.
+ /// The repository PersistNewItem method.
+ /// Creates the entity in the repository, and updates the cache accordingly.
+ void Create(TEntity entity, Action persistNew);
+
+ ///
+ /// Updates an entity.
+ ///
+ /// The entity.
+ /// The reopsitory PersistUpdatedItem method.
+ /// Updates the entity in the repository, and updates the cache accordingly.
+ void Update(TEntity entity, Action persistUpdated);
+
+ ///
+ /// Removes an entity.
+ ///
+ /// The entity.
+ /// The repository PersistDeletedItem method.
+ /// Removes the entity from the repository and clears the cache.
+ void Delete(TEntity entity, Action persistDeleted);
+
+ ///
+ /// Gets entities.
+ ///
+ /// The identifiers.
+ /// The repository PerformGetAll method.
+ /// If is empty, all entities, else the entities with the specified identifiers.
+ /// Get all the entities. Either from the cache or the repository depending on the implementation.
+ TEntity[] GetAll(TId[] ids, Func> performGetAll);
+
+ ///
+ /// Clears the entire cache.
+ ///
+ void ClearAll();
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Cache/IRepositoryCachePolicyFactory.cs b/src/Umbraco.Core/Cache/IRepositoryCachePolicyFactory.cs
deleted file mode 100644
index 2d69704b63..0000000000
--- a/src/Umbraco.Core/Cache/IRepositoryCachePolicyFactory.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using Umbraco.Core.Models.EntityBase;
-
-namespace Umbraco.Core.Cache
-{
- internal interface IRepositoryCachePolicyFactory where TEntity : class, IAggregateRoot
- {
- IRepositoryCachePolicy CreatePolicy();
- }
-}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Cache/NoRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/NoRepositoryCachePolicy.cs
new file mode 100644
index 0000000000..54891af48b
--- /dev/null
+++ b/src/Umbraco.Core/Cache/NoRepositoryCachePolicy.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Umbraco.Core.Models.EntityBase;
+using Umbraco.Core.Scoping;
+
+namespace Umbraco.Core.Cache
+{
+ internal class NoRepositoryCachePolicy : IRepositoryCachePolicy
+ where TEntity : class, IAggregateRoot
+ {
+ private static readonly NoRepositoryCachePolicy StaticInstance = new NoRepositoryCachePolicy();
+
+ private NoRepositoryCachePolicy()
+ { }
+
+ public static NoRepositoryCachePolicy Instance { get { return StaticInstance; } }
+
+ public IRepositoryCachePolicy Scoped(IRuntimeCacheProvider runtimeCache, IScope scope)
+ {
+ throw new NotImplementedException();
+ }
+
+ public TEntity Get(TId id, Func performGet, Func> performGetAll)
+ {
+ return performGet(id);
+ }
+
+ public TEntity GetCached(TId id)
+ {
+ return null;
+ }
+
+ public bool Exists(TId id, Func performExists, Func> performGetAll)
+ {
+ return performExists(id);
+ }
+
+ public void Create(TEntity entity, Action persistNew)
+ {
+ persistNew(entity);
+ }
+
+ public void Update(TEntity entity, Action persistUpdated)
+ {
+ persistUpdated(entity);
+ }
+
+ public void Delete(TEntity entity, Action persistDeleted)
+ {
+ persistDeleted(entity);
+ }
+
+ public TEntity[] GetAll(TId[] ids, Func> performGetAll)
+ {
+ return performGetAll(ids).ToArray();
+ }
+
+ public void ClearAll()
+ { }
+ }
+}
diff --git a/src/Umbraco.Core/Cache/OnlySingleItemsRepositoryCachePolicyFactory.cs b/src/Umbraco.Core/Cache/OnlySingleItemsRepositoryCachePolicyFactory.cs
deleted file mode 100644
index b24838bc3b..0000000000
--- a/src/Umbraco.Core/Cache/OnlySingleItemsRepositoryCachePolicyFactory.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using Umbraco.Core.Models.EntityBase;
-
-namespace Umbraco.Core.Cache
-{
- ///
- /// Creates cache policies
- ///
- ///
- ///
- internal class OnlySingleItemsRepositoryCachePolicyFactory : IRepositoryCachePolicyFactory
- where TEntity : class, IAggregateRoot
- {
- private readonly IRuntimeCacheProvider _runtimeCache;
- private readonly RepositoryCachePolicyOptions _options;
-
- public OnlySingleItemsRepositoryCachePolicyFactory(IRuntimeCacheProvider runtimeCache, RepositoryCachePolicyOptions options)
- {
- _runtimeCache = runtimeCache;
- _options = options;
- }
-
- public virtual IRepositoryCachePolicy CreatePolicy()
- {
- return new SingleItemsOnlyRepositoryCachePolicy(_runtimeCache, _options);
- }
- }
-}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Cache/RepositoryCachePolicyBase.cs b/src/Umbraco.Core/Cache/RepositoryCachePolicyBase.cs
index b939cd14e6..0b5d2b15c5 100644
--- a/src/Umbraco.Core/Cache/RepositoryCachePolicyBase.cs
+++ b/src/Umbraco.Core/Cache/RepositoryCachePolicyBase.cs
@@ -1,48 +1,51 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Models.EntityBase;
+using Umbraco.Core.Scoping;
namespace Umbraco.Core.Cache
{
- internal abstract class RepositoryCachePolicyBase : DisposableObject, IRepositoryCachePolicy
+ ///
+ /// A base class for repository cache policies.
+ ///
+ /// The type of the entity.
+ /// The type of the identifier.
+ internal abstract class RepositoryCachePolicyBase : IRepositoryCachePolicy
where TEntity : class, IAggregateRoot
{
- private Action _action;
-
protected RepositoryCachePolicyBase(IRuntimeCacheProvider cache)
{
- if (cache == null) throw new ArgumentNullException("cache");
-
+ if (cache == null) throw new ArgumentNullException("cache");
Cache = cache;
}
+ public abstract IRepositoryCachePolicy Scoped(IRuntimeCacheProvider runtimeCache, IScope scope);
+
protected IRuntimeCacheProvider Cache { get; private set; }
- ///
- /// The disposal performs the caching
- ///
- protected override void DisposeResources()
- {
- if (_action != null)
- {
- _action();
- }
- }
+ ///
+ public abstract TEntity Get(TId id, Func performGet, Func> performGetAll);
- ///
- /// Sets the action to execute on disposal
- ///
- ///
- protected void SetCacheAction(Action action)
- {
- _action = action;
- }
+ ///
+ public abstract TEntity GetCached(TId id);
+
+ ///
+ public abstract bool Exists(TId id, Func performExists, Func> performGetAll);
+
+ ///
+ public abstract void Create(TEntity entity, Action persistNew);
+
+ ///
+ public abstract void Update(TEntity entity, Action persistUpdated);
+
+ ///
+ public abstract void Delete(TEntity entity, Action persistDeleted);
+
+ ///
+ public abstract TEntity[] GetAll(TId[] ids, Func> performGetAll);
+
+ ///
+ public abstract void ClearAll();
- public abstract TEntity Get(TId id, Func getFromRepo);
- public abstract TEntity Get(TId id);
- public abstract bool Exists(TId id, Func getFromRepo);
- public abstract void CreateOrUpdate(TEntity entity, Action persistMethod);
- public abstract void Remove(TEntity entity, Action persistMethod);
- public abstract TEntity[] GetAll(TId[] ids, Func> getFromRepo);
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Cache/RepositoryCachePolicyOptions.cs b/src/Umbraco.Core/Cache/RepositoryCachePolicyOptions.cs
index e8c6ac02b0..14cef76db6 100644
--- a/src/Umbraco.Core/Cache/RepositoryCachePolicyOptions.cs
+++ b/src/Umbraco.Core/Cache/RepositoryCachePolicyOptions.cs
@@ -2,6 +2,9 @@ using System;
namespace Umbraco.Core.Cache
{
+ ///
+ /// Specifies how a repository cache policy should cache entities.
+ ///
internal class RepositoryCachePolicyOptions
{
///
diff --git a/src/Umbraco.Core/Cache/ScopedRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/ScopedRepositoryCachePolicy.cs
new file mode 100644
index 0000000000..f4244a49a1
--- /dev/null
+++ b/src/Umbraco.Core/Cache/ScopedRepositoryCachePolicy.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Collections.Generic;
+using Umbraco.Core.Models.EntityBase;
+using Umbraco.Core.Scoping;
+
+namespace Umbraco.Core.Cache
+{
+ internal class ScopedRepositoryCachePolicy : IRepositoryCachePolicy
+ where TEntity : class, IAggregateRoot
+ {
+ private readonly IRepositoryCachePolicy _cachePolicy;
+ private readonly IRuntimeCacheProvider _globalIsolatedCache;
+ private readonly IScope _scope;
+
+ public ScopedRepositoryCachePolicy(IRepositoryCachePolicy cachePolicy, IRuntimeCacheProvider globalIsolatedCache, IScope scope)
+ {
+ _cachePolicy = cachePolicy;
+ _globalIsolatedCache = globalIsolatedCache;
+ _scope = scope;
+ }
+
+ public IRepositoryCachePolicy Scoped(IRuntimeCacheProvider runtimeCache, IScope scope)
+ {
+ throw new InvalidOperationException(); // obviously
+ }
+
+ public TEntity Get(TId id, Func performGet, Func> performGetAll)
+ {
+ // loads into the local cache only, ok for now
+ return _cachePolicy.Get(id, performGet, performGetAll);
+ }
+
+ public TEntity GetCached(TId id)
+ {
+ // loads into the local cache only, ok for now
+ return _cachePolicy.GetCached(id);
+ }
+
+ public bool Exists(TId id, Func performExists, Func> performGetAll)
+ {
+ // loads into the local cache only, ok for now
+ return _cachePolicy.Exists(id, performExists, performGetAll);
+ }
+
+ public void Create(TEntity entity, Action persistNew)
+ {
+ // writes into the local cache
+ _cachePolicy.Create(entity, persistNew);
+ }
+
+ public void Update(TEntity entity, Action persistUpdated)
+ {
+ // writes into the local cache
+ _cachePolicy.Update(entity, persistUpdated);
+ }
+
+ public void Delete(TEntity entity, Action persistDeleted)
+ {
+ // deletes the local cache
+ _cachePolicy.Delete(entity, persistDeleted);
+ }
+
+ public TEntity[] GetAll(TId[] ids, Func> performGetAll)
+ {
+ // loads into the local cache only, ok for now
+ return _cachePolicy.GetAll(ids, performGetAll);
+ }
+
+ public void ClearAll()
+ {
+ // clears the local cache
+ _cachePolicy.ClearAll();
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Cache/SingleItemsOnlyRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/SingleItemsOnlyRepositoryCachePolicy.cs
index 28ac4ee2d1..7ba7d445fe 100644
--- a/src/Umbraco.Core/Cache/SingleItemsOnlyRepositoryCachePolicy.cs
+++ b/src/Umbraco.Core/Cache/SingleItemsOnlyRepositoryCachePolicy.cs
@@ -1,24 +1,27 @@
-using System.Linq;
-using Umbraco.Core.Collections;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Cache
{
///
- /// A caching policy that ignores all caches for GetAll - it will only cache calls for individual items
+ /// Represents a special policy that does not cache the result of GetAll.
///
- ///
- ///
+ /// The type of the entity.
+ /// The type of the identifier.
+ ///
+ /// Overrides the default repository cache policy and does not writes the result of GetAll
+ /// to cache, but only the result of individual Gets. It does read the cache for GetAll, though.
+ /// Used by DictionaryRepository.
+ ///
internal class SingleItemsOnlyRepositoryCachePolicy : DefaultRepositoryCachePolicy
where TEntity : class, IAggregateRoot
{
- public SingleItemsOnlyRepositoryCachePolicy(IRuntimeCacheProvider cache, RepositoryCachePolicyOptions options) : base(cache, options)
+ public SingleItemsOnlyRepositoryCachePolicy(IRuntimeCacheProvider cache, RepositoryCachePolicyOptions options)
+ : base(cache, options)
+ { }
+
+ protected override void InsertEntities(TId[] ids, TEntity[] entities)
{
- }
-
- protected override void SetCacheAction(TId[] ids, TEntity[] entityCollection)
- {
- //no-op
+ // nop
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/CacheHelper.cs b/src/Umbraco.Core/CacheHelper.cs
index 0dc5f5b00f..dbf3f89714 100644
--- a/src/Umbraco.Core/CacheHelper.cs
+++ b/src/Umbraco.Core/CacheHelper.cs
@@ -21,6 +21,10 @@ namespace Umbraco.Core
private static readonly ICacheProvider NullRequestCache = new NullCacheProvider();
private static readonly ICacheProvider NullStaticCache = new NullCacheProvider();
private static readonly IRuntimeCacheProvider NullRuntimeCache = new NullCacheProvider();
+ private static readonly IsolatedRuntimeCache NullIsolatedCache = new IsolatedRuntimeCache(_ => NullRuntimeCache);
+ private static readonly CacheHelper NullCache = new CacheHelper(NullRuntimeCache, NullStaticCache, NullRequestCache, NullIsolatedCache);
+
+ public static CacheHelper NoCache { get { return NullCache; } }
///
/// Creates a cache helper with disabled caches
@@ -31,7 +35,10 @@ namespace Umbraco.Core
///
public static CacheHelper CreateDisabledCacheHelper()
{
- return new CacheHelper(NullRuntimeCache, NullStaticCache, NullRequestCache, new IsolatedRuntimeCache(t => NullRuntimeCache));
+ // do *not* return NoCache
+ // NoCache is a special instance that is detected by RepositoryBase and disables all cache policies
+ // CreateDisabledCacheHelper is used in tests to use no cache, *but* keep all cache policies
+ return new CacheHelper(NullRuntimeCache, NullStaticCache, NullRequestCache, NullIsolatedCache);
}
///
diff --git a/src/Umbraco.Core/CodeAnnotations/UmbracoUdiTypeAttribute.cs b/src/Umbraco.Core/CodeAnnotations/UmbracoUdiTypeAttribute.cs
new file mode 100644
index 0000000000..0bb9de6c86
--- /dev/null
+++ b/src/Umbraco.Core/CodeAnnotations/UmbracoUdiTypeAttribute.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Umbraco.Core.CodeAnnotations
+{
+ [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
+ internal class UmbracoUdiTypeAttribute : Attribute
+ {
+ public string UdiType { get; private set; }
+
+ public UmbracoUdiTypeAttribute(string udiType)
+ {
+ UdiType = udiType;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Configuration/GlobalSettings.cs b/src/Umbraco.Core/Configuration/GlobalSettings.cs
index 525bff2999..c28f398333 100644
--- a/src/Umbraco.Core/Configuration/GlobalSettings.cs
+++ b/src/Umbraco.Core/Configuration/GlobalSettings.cs
@@ -212,7 +212,7 @@ namespace Umbraco.Core.Configuration
{
get
{
- var settings = ConfigurationManager.ConnectionStrings[UmbracoConnectionName];
+ var settings = ConfigurationManager.ConnectionStrings[Constants.System.UmbracoConnectionName];
var connectionString = string.Empty;
if (settings != null)
@@ -241,10 +241,7 @@ namespace Umbraco.Core.Configuration
}
}
}
-
- //TODO: Move these to constants!
- public const string UmbracoConnectionName = "umbracoDbDSN";
- public const string UmbracoMigrationName = "Umbraco";
+
///
/// Gets or sets the configuration status. This will return the version number of the currently installed umbraco instance.
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs
index 7169a3a80b..04e57c5e1d 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs
@@ -4,8 +4,7 @@ using System.Configuration;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
-
- internal class ContentElement : ConfigurationElement, IContentSection
+ internal class ContentElement : UmbracoConfigurationElement, IContentSection
{
[ConfigurationProperty("imaging")]
internal ContentImagingElement Imaging
@@ -22,25 +21,13 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
[ConfigurationProperty("ResolveUrlsFromTextString")]
internal InnerTextConfigurationElement ResolveUrlsFromTextString
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["ResolveUrlsFromTextString"],
- //set the default
- false);
- }
+ get { return GetOptionalTextElement("ResolveUrlsFromTextString", false); }
}
[ConfigurationProperty("UploadAllowDirectories")]
internal InnerTextConfigurationElement UploadAllowDirectories
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["UploadAllowDirectories"],
- //set the default
- true);
- }
+ get { return GetOptionalTextElement("UploadAllowDirectories", true); }
}
public IEnumerable Error404Collection
@@ -63,121 +50,61 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
[ConfigurationProperty("ensureUniqueNaming")]
internal InnerTextConfigurationElement EnsureUniqueNaming
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["ensureUniqueNaming"],
- //set the default
- true);
- }
+ get { return GetOptionalTextElement("ensureUniqueNaming", true); }
}
[ConfigurationProperty("TidyEditorContent")]
internal InnerTextConfigurationElement TidyEditorContent
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["TidyEditorContent"],
- //set the default
- false);
- }
+ get { return GetOptionalTextElement("TidyEditorContent", false); }
}
[ConfigurationProperty("TidyCharEncoding")]
internal InnerTextConfigurationElement TidyCharEncoding
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["TidyCharEncoding"],
- //set the default
- "UTF8");
- }
+ get { return GetOptionalTextElement("TidyCharEncoding", "UTF8"); }
}
[ConfigurationProperty("XmlCacheEnabled")]
internal InnerTextConfigurationElement XmlCacheEnabled
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["XmlCacheEnabled"],
- //set the default
- true);
- }
+ get { return GetOptionalTextElement("XmlCacheEnabled", true); }
}
[ConfigurationProperty("ContinouslyUpdateXmlDiskCache")]
internal InnerTextConfigurationElement ContinouslyUpdateXmlDiskCache
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["ContinouslyUpdateXmlDiskCache"],
- //set the default
- true);
- }
+ get { return GetOptionalTextElement("ContinouslyUpdateXmlDiskCache", true); }
}
[ConfigurationProperty("XmlContentCheckForDiskChanges")]
internal InnerTextConfigurationElement XmlContentCheckForDiskChanges
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["XmlContentCheckForDiskChanges"],
- //set the default
- false);
- }
+ get { return GetOptionalTextElement("XmlContentCheckForDiskChanges", false); }
}
[ConfigurationProperty("EnableSplashWhileLoading")]
internal InnerTextConfigurationElement EnableSplashWhileLoading
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["EnableSplashWhileLoading"],
- //set the default
- false);
- }
+ get { return GetOptionalTextElement("EnableSplashWhileLoading", false); }
}
[ConfigurationProperty("PropertyContextHelpOption")]
internal InnerTextConfigurationElement PropertyContextHelpOption
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["PropertyContextHelpOption"],
- //set the default
- "text");
- }
+ get { return GetOptionalTextElement("PropertyContextHelpOption", "text"); }
}
[ConfigurationProperty("UseLegacyXmlSchema")]
internal InnerTextConfigurationElement UseLegacyXmlSchema
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["UseLegacyXmlSchema"],
- //set the default
- false);
- }
+ get { return GetOptionalTextElement("UseLegacyXmlSchema", false); }
}
[ConfigurationProperty("ForceSafeAliases")]
internal InnerTextConfigurationElement ForceSafeAliases
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["ForceSafeAliases"],
- //set the default
- true);
- }
+ get { return GetOptionalTextElement("ForceSafeAliases", true); }
}
[ConfigurationProperty("PreviewBadge")]
@@ -185,123 +112,69 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
{
get
{
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["PreviewBadge"],
- //set the default
- @"In Preview Mode - click to end");
+ return GetOptionalTextElement("PreviewBadge", @"In Preview Mode - click to end");
}
}
[ConfigurationProperty("UmbracoLibraryCacheDuration")]
internal InnerTextConfigurationElement UmbracoLibraryCacheDuration
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["UmbracoLibraryCacheDuration"],
- //set the default
- 1800);
-
- }
+ get { return GetOptionalTextElement("UmbracoLibraryCacheDuration", 1800); }
}
[ConfigurationProperty("MacroErrors")]
internal InnerTextConfigurationElement MacroErrors
{
- get
- {
-
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["MacroErrors"],
- //set the default
- MacroErrorBehaviour.Inline);
- }
+ get { return GetOptionalTextElement("MacroErrors", MacroErrorBehaviour.Inline); }
}
[Obsolete("This is here so that if this config element exists we won't get a YSOD, it is not used whatsoever and will be removed in future versions")]
[ConfigurationProperty("DocumentTypeIconList")]
internal InnerTextConfigurationElement DocumentTypeIconList
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["DocumentTypeIconList"],
- //set the default
- IconPickerBehaviour.HideFileDuplicates);
- }
+ get { return GetOptionalTextElement("DocumentTypeIconList", IconPickerBehaviour.HideFileDuplicates); }
}
[ConfigurationProperty("disallowedUploadFiles")]
internal CommaDelimitedConfigurationElement DisallowedUploadFiles
{
- get
- {
- return new OptionalCommaDelimitedConfigurationElement(
- (CommaDelimitedConfigurationElement)this["disallowedUploadFiles"],
- //set the default
- new[] { "ashx", "aspx", "ascx", "config", "cshtml", "vbhtml", "asmx", "air", "axd" });
-
- }
+ get { return GetOptionalDelimitedElement("disallowedUploadFiles", new[] {"ashx", "aspx", "ascx", "config", "cshtml", "vbhtml", "asmx", "air", "axd"}); }
}
[ConfigurationProperty("cloneXmlContent")]
internal InnerTextConfigurationElement CloneXmlContent
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["cloneXmlContent"],
- //set the default
- true);
- }
+ get { return GetOptionalTextElement("cloneXmlContent", true); }
}
[ConfigurationProperty("GlobalPreviewStorageEnabled")]
internal InnerTextConfigurationElement GlobalPreviewStorageEnabled
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["GlobalPreviewStorageEnabled"],
- //set the default
- false);
- }
+ get { return GetOptionalTextElement("GlobalPreviewStorageEnabled", false); }
}
[ConfigurationProperty("defaultDocumentTypeProperty")]
internal InnerTextConfigurationElement DefaultDocumentTypeProperty
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["defaultDocumentTypeProperty"],
- //set the default
- "Textstring");
- }
+ get { return GetOptionalTextElement("defaultDocumentTypeProperty", "Textstring"); }
+ }
+
+ [ConfigurationProperty("showDeprecatedPropertyEditors")]
+ internal InnerTextConfigurationElement ShowDeprecatedPropertyEditors
+ {
+ get { return GetOptionalTextElement("showDeprecatedPropertyEditors", false); }
}
[ConfigurationProperty("EnableInheritedDocumentTypes")]
internal InnerTextConfigurationElement EnableInheritedDocumentTypes
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement) this["EnableInheritedDocumentTypes"],
- //set the default
- true);
- }
+ get { return GetOptionalTextElement("EnableInheritedDocumentTypes", true); }
}
[ConfigurationProperty("EnableInheritedMediaTypes")]
internal InnerTextConfigurationElement EnableInheritedMediaTypes
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["EnableInheritedMediaTypes"],
- //set the default
- true);
- }
+ get { return GetOptionalTextElement("EnableInheritedMediaTypes", true); }
}
[ConfigurationProperty("EnablePropertyValueConverters")]
@@ -451,6 +324,11 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
get { return DefaultDocumentTypeProperty; }
}
+ bool IContentSection.ShowDeprecatedPropertyEditors
+ {
+ get { return ShowDeprecatedPropertyEditors; }
+ }
+
bool IContentSection.EnableInheritedDocumentTypes
{
get { return EnableInheritedDocumentTypes; }
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/ContentScriptEditorElement.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/ContentScriptEditorElement.cs
index 0d14609caa..f60e964a04 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/ContentScriptEditorElement.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/ContentScriptEditorElement.cs
@@ -3,42 +3,24 @@ using System.Configuration;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
- internal class ContentScriptEditorElement : ConfigurationElement
+ internal class ContentScriptEditorElement : UmbracoConfigurationElement
{
[ConfigurationProperty("scriptFolderPath")]
internal InnerTextConfigurationElement ScriptFolderPath
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["scriptFolderPath"],
- //set the default
- "/scripts");
- }
+ get { return GetOptionalTextElement("scriptFolderPath", "/scripts"); }
}
[ConfigurationProperty("scriptFileTypes")]
internal OptionalCommaDelimitedConfigurationElement ScriptFileTypes
{
- get
- {
- return new OptionalCommaDelimitedConfigurationElement(
- (OptionalCommaDelimitedConfigurationElement)this["scriptFileTypes"],
- //set the default
- new[] { "js", "xml" });
- }
+ get { return GetOptionalDelimitedElement("scriptFileTypes", new[] {"js", "xml"}); }
}
[ConfigurationProperty("scriptDisableEditor")]
internal InnerTextConfigurationElement ScriptEditorDisable
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement) this["scriptDisableEditor"],
- //set the default
- false);
- }
+ get { return GetOptionalTextElement("scriptDisableEditor", false); }
}
}
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs
index 4b9c0304ce..5dbf9f1a33 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs
@@ -60,6 +60,12 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
string DefaultDocumentTypeProperty { get; }
+ ///
+ /// The default for this is false but if you would like deprecated property editors displayed
+ /// in the data type editor you can enable this
+ ///
+ bool ShowDeprecatedPropertyEditors { get; }
+
bool EnableInheritedDocumentTypes { get; }
bool EnableInheritedMediaTypes { get; }
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/ImagingAutoFillUploadFieldElement.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/ImagingAutoFillUploadFieldElement.cs
index 0dfc4afc00..eafe43817d 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/ImagingAutoFillUploadFieldElement.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/ImagingAutoFillUploadFieldElement.cs
@@ -2,7 +2,7 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
- internal class ImagingAutoFillUploadFieldElement : ConfigurationElement, IImagingAutoFillUploadField
+ internal class ImagingAutoFillUploadFieldElement : UmbracoConfigurationElement, IImagingAutoFillUploadField
{
///
/// Allow setting internally so we can create a default
@@ -17,49 +17,25 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
[ConfigurationProperty("widthFieldAlias")]
internal InnerTextConfigurationElement WidthFieldAlias
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["widthFieldAlias"],
- //set the default
- "umbracoWidth");
- }
+ get { return GetOptionalTextElement("widthFieldAlias", "umbracoWidth"); }
}
[ConfigurationProperty("heightFieldAlias")]
internal InnerTextConfigurationElement HeightFieldAlias
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["heightFieldAlias"],
- //set the default
- "umbracoHeight");
- }
+ get { return GetOptionalTextElement("heightFieldAlias", "umbracoHeight"); }
}
[ConfigurationProperty("lengthFieldAlias")]
internal InnerTextConfigurationElement LengthFieldAlias
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["lengthFieldAlias"],
- //set the default
- "umbracoBytes");
- }
+ get { return GetOptionalTextElement("lengthFieldAlias", "umbracoBytes"); }
}
[ConfigurationProperty("extensionFieldAlias")]
internal InnerTextConfigurationElement ExtensionFieldAlias
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["extensionFieldAlias"],
- //set the default
- "umbracoExtension");
- }
+ get { return GetOptionalTextElement("extensionFieldAlias", "umbracoExtension"); }
}
string IImagingAutoFillUploadField.Alias
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/LoggingElement.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/LoggingElement.cs
index f95a9c7e76..39e6327b3a 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/LoggingElement.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/LoggingElement.cs
@@ -3,67 +3,37 @@ using System.Configuration;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
- internal class LoggingElement : ConfigurationElement, ILoggingSection
+ internal class LoggingElement : UmbracoConfigurationElement, ILoggingSection
{
[ConfigurationProperty("autoCleanLogs")]
internal InnerTextConfigurationElement AutoCleanLogs
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["autoCleanLogs"],
- //set the default
- false);
- }
+ get { return GetOptionalTextElement("autoCleanLogs", false); }
}
[ConfigurationProperty("enableLogging")]
internal InnerTextConfigurationElement EnableLogging
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["enableLogging"],
- //set the default
- true);
- }
+ get { return GetOptionalTextElement("enableLogging", true); }
}
[ConfigurationProperty("enableAsyncLogging")]
internal InnerTextConfigurationElement EnableAsyncLogging
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["enableAsyncLogging"],
- //set the default
- true);
- }
+ get { return GetOptionalTextElement("enableAsyncLogging", true); }
}
[ConfigurationProperty("cleaningMiliseconds")]
internal InnerTextConfigurationElement CleaningMiliseconds
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["cleaningMiliseconds"],
- //set the default
- -1);
- }
+ get { return GetOptionalTextElement("cleaningMiliseconds", -1); }
}
[ConfigurationProperty("maxLogAge")]
internal InnerTextConfigurationElement MaxLogAge
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["maxLogAge"],
- //set the default
- -1);
- }
+ get { return GetOptionalTextElement("maxLogAge", -1); }
}
[ConfigurationCollection(typeof(DisabledLogTypesCollection), AddItemName = "logTypeAlias")]
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/NotificationsElement.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/NotificationsElement.cs
index 16eb943887..89e3f447ee 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/NotificationsElement.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/NotificationsElement.cs
@@ -2,7 +2,7 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
{
- internal class NotificationsElement : ConfigurationElement
+ internal class NotificationsElement : UmbracoConfigurationElement
{
[ConfigurationProperty("email")]
internal InnerTextConfigurationElement NotificationEmailAddress
@@ -13,13 +13,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
[ConfigurationProperty("disableHtmlEmail")]
internal InnerTextConfigurationElement DisableHtmlEmail
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement) this["disableHtmlEmail"],
- //set the default
- false);
- }
+ get { return GetOptionalTextElement("disableHtmlEmail", false); }
}
}
diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/RequestHandlerElement.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/RequestHandlerElement.cs
index 9dc4a94824..779d33c8b8 100644
--- a/src/Umbraco.Core/Configuration/UmbracoSettings/RequestHandlerElement.cs
+++ b/src/Umbraco.Core/Configuration/UmbracoSettings/RequestHandlerElement.cs
@@ -5,30 +5,18 @@ using System.Collections.Generic;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
- internal class RequestHandlerElement : ConfigurationElement, IRequestHandlerSection
+ internal class RequestHandlerElement : UmbracoConfigurationElement, IRequestHandlerSection
{
[ConfigurationProperty("useDomainPrefixes")]
public InnerTextConfigurationElement UseDomainPrefixes
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement)this["useDomainPrefixes"],
- //set the default
- false);
- }
+ get { return GetOptionalTextElement("useDomainPrefixes", false); }
}
[ConfigurationProperty("addTrailingSlash")]
public InnerTextConfigurationElement AddTrailingSlash
{
- get
- {
- return new OptionalInnerTextConfigurationElement(
- (InnerTextConfigurationElement