Creates IDisposeOnRequestEnd and ensures UmbracoContext and UmbracoDatabase implement it, then we only dispose of these types of objects at the end of the request if they are part of the httpcontext items (U4-2738). Fixes: U4-2988 UmbracoObjectTypesExtensions is not thread safe

This commit is contained in:
Shannon
2013-09-30 12:02:35 +10:00
parent 099c1ff2ea
commit 957760d29a
6 changed files with 38 additions and 19 deletions

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Umbraco.Core
{
/// <summary>
/// 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.
/// </summary>
public interface IDisposeOnRequestEnd : IDisposable
{
}
}

View File

@@ -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
/// </summary>
public static class UmbracoObjectTypesExtensions
{
private static readonly Dictionary<UmbracoObjectTypes, Guid> UmbracoObjectTypeCache = new Dictionary<UmbracoObjectTypes,Guid>();
//MUST be concurrent to avoid thread collisions!
private static readonly ConcurrentDictionary<UmbracoObjectTypes, Guid> UmbracoObjectTypeCache = new ConcurrentDictionary<UmbracoObjectTypes, Guid>();
/// <summary>
/// Get an UmbracoObjectTypes value from it's name
@@ -48,24 +50,22 @@ namespace Umbraco.Core.Models
/// <returns>a GUID value of the UmbracoObjectTypes</returns>
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;
});
}
/// <summary>

View File

@@ -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.
/// </remarks>
public class UmbracoDatabase : Database
public class UmbracoDatabase : Database, IDisposeOnRequestEnd
{
private readonly Guid _instanceId = Guid.NewGuid();
/// <summary>

View File

@@ -166,6 +166,7 @@
<Compile Include="Events\SaveEventArgs.cs" />
<Compile Include="Events\SendToPublishEventArgs.cs" />
<Compile Include="IApplicationEventHandler.cs" />
<Compile Include="IDisposeOnRequestEnd.cs" />
<Compile Include="IO\ResizedImage.cs" />
<Compile Include="IO\UmbracoMediaFile.cs" />
<Compile Include="Media\MediaSubfolderCounter.cs" />

View File

@@ -24,7 +24,7 @@ namespace Umbraco.Web
/// <summary>
/// Class that encapsulates Umbraco information of a specific HTTP request
/// </summary>
public class UmbracoContext : DisposableObject
public class UmbracoContext : DisposableObject, IDisposeOnRequestEnd
{
private const string HttpContextItemName = "Umbraco.Web.UmbracoContext";
private static readonly object Locker = new object();

View File

@@ -467,11 +467,15 @@ namespace Umbraco.Web
/// <param name="http"></param>
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<object>();
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);
}