diff --git a/src/Umbraco.Core/IDisposeOnRequestEnd.cs b/src/Umbraco.Core/IDisposeOnRequestEnd.cs new file mode 100644 index 0000000000..cf1ec3a177 --- /dev/null +++ b/src/Umbraco.Core/IDisposeOnRequestEnd.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Umbraco.Core +{ + /// + /// Any class implementing this interface that is added to the httpcontext.items keys or values will be disposed of at the end of the request. + /// + public interface IDisposeOnRequestEnd : IDisposable + { + } +} diff --git a/src/Umbraco.Core/Models/UmbracoObjectTypesExtensions.cs b/src/Umbraco.Core/Models/UmbracoObjectTypesExtensions.cs index a97f1fe976..7cc130600b 100644 --- a/src/Umbraco.Core/Models/UmbracoObjectTypesExtensions.cs +++ b/src/Umbraco.Core/Models/UmbracoObjectTypesExtensions.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using Umbraco.Core.CodeAnnotations; @@ -9,7 +10,8 @@ namespace Umbraco.Core.Models /// public static class UmbracoObjectTypesExtensions { - private static readonly Dictionary UmbracoObjectTypeCache = new Dictionary(); + //MUST be concurrent to avoid thread collisions! + private static readonly ConcurrentDictionary UmbracoObjectTypeCache = new ConcurrentDictionary(); /// /// Get an UmbracoObjectTypes value from it's name @@ -48,24 +50,22 @@ namespace Umbraco.Core.Models /// a GUID value of the UmbracoObjectTypes public static Guid GetGuid(this UmbracoObjectTypes umbracoObjectType) { - if (UmbracoObjectTypeCache.ContainsKey(umbracoObjectType)) - return UmbracoObjectTypeCache[umbracoObjectType]; + return UmbracoObjectTypeCache.GetOrAdd(umbracoObjectType, types => + { + var type = typeof(UmbracoObjectTypes); + var memInfo = type.GetMember(umbracoObjectType.ToString()); + var attributes = memInfo[0].GetCustomAttributes(typeof(UmbracoObjectTypeAttribute), + false); - var type = typeof(UmbracoObjectTypes); - var memInfo = type.GetMember(umbracoObjectType.ToString()); - var attributes = memInfo[0].GetCustomAttributes(typeof(UmbracoObjectTypeAttribute), - false); + if (attributes.Length == 0) + return Guid.Empty; - if (attributes.Length == 0) - return Guid.Empty; + var attribute = ((UmbracoObjectTypeAttribute)attributes[0]); + if (attribute == null) + return Guid.Empty; - var attribute = ((UmbracoObjectTypeAttribute)attributes[0]); - if (attribute == null) - return Guid.Empty; - - UmbracoObjectTypeCache.Add(umbracoObjectType, attribute.ObjectId); - - return attribute.ObjectId; + return attribute.ObjectId; + }); } /// diff --git a/src/Umbraco.Core/Persistence/UmbracoDatabase.cs b/src/Umbraco.Core/Persistence/UmbracoDatabase.cs index 522e0b4173..98d5d9cebc 100644 --- a/src/Umbraco.Core/Persistence/UmbracoDatabase.cs +++ b/src/Umbraco.Core/Persistence/UmbracoDatabase.cs @@ -16,7 +16,7 @@ namespace Umbraco.Core.Persistence /// can then override any additional execution (such as additional loggging, functionality, etc...) that we need to without breaking compatibility since we'll always be exposing /// this object instead of the base PetaPoco database object. /// - public class UmbracoDatabase : Database + public class UmbracoDatabase : Database, IDisposeOnRequestEnd { private readonly Guid _instanceId = Guid.NewGuid(); /// diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 2cc6a8fbd4..dc95d29ab4 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -166,6 +166,7 @@ + diff --git a/src/Umbraco.Web/UmbracoContext.cs b/src/Umbraco.Web/UmbracoContext.cs index 17751b4077..2458dc62e0 100644 --- a/src/Umbraco.Web/UmbracoContext.cs +++ b/src/Umbraco.Web/UmbracoContext.cs @@ -24,7 +24,7 @@ namespace Umbraco.Web /// /// Class that encapsulates Umbraco information of a specific HTTP request /// - public class UmbracoContext : DisposableObject + public class UmbracoContext : DisposableObject, IDisposeOnRequestEnd { private const string HttpContextItemName = "Umbraco.Web.UmbracoContext"; private static readonly object Locker = new object(); diff --git a/src/Umbraco.Web/UmbracoModule.cs b/src/Umbraco.Web/UmbracoModule.cs index 79f029c4a7..5ba568c56e 100644 --- a/src/Umbraco.Web/UmbracoModule.cs +++ b/src/Umbraco.Web/UmbracoModule.cs @@ -467,11 +467,15 @@ namespace Umbraco.Web /// private static void DisposeHttpContextItems(HttpContext http) { + // do not process if client-side request + if (http.Request.Url.IsClientSideRequest()) + return; + //get a list of keys to dispose var keys = new HashSet(); foreach (DictionaryEntry i in http.Items) { - if (i.Value is IDisposable || i.Key is IDisposable) + if (i.Value is IDisposeOnRequestEnd || i.Key is IDisposeOnRequestEnd) { keys.Add(i.Key); }