Namespace and file cleanup - Profiling --> Logging, root cache stuff moved to Cache, XmlHelper --> Xml, TypeFinder, etc.. --> Plugins
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Threading;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
|
||||
@@ -1,428 +1,421 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using System.Web.Caching;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Class that is exposed by the ApplicationContext for application wide caching purposes
|
||||
/// </summary>
|
||||
public class CacheHelper
|
||||
{
|
||||
private static readonly ICacheProvider NullRequestCache = new NullCacheProvider();
|
||||
private static readonly ICacheProvider NullStaticCache = new NullCacheProvider();
|
||||
private static readonly IRuntimeCacheProvider NullRuntimeCache = new NullCacheProvider();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a cache helper with disabled caches
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// Good for unit testing
|
||||
/// </remarks>
|
||||
public static CacheHelper CreateDisabledCacheHelper()
|
||||
{
|
||||
return new CacheHelper(NullRuntimeCache, NullStaticCache, NullRequestCache, new IsolatedRuntimeCache(t => NullRuntimeCache));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance for use in the web
|
||||
/// </summary>
|
||||
public CacheHelper()
|
||||
: this(
|
||||
new HttpRuntimeCacheProvider(HttpRuntime.Cache),
|
||||
new StaticCacheProvider(),
|
||||
new HttpRequestCacheProvider(),
|
||||
new IsolatedRuntimeCache(t => new ObjectCacheRuntimeCacheProvider()))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance for use in the web
|
||||
/// </summary>
|
||||
/// <param name="cache"></param>
|
||||
public CacheHelper(System.Web.Caching.Cache cache)
|
||||
: this(
|
||||
new HttpRuntimeCacheProvider(cache),
|
||||
new StaticCacheProvider(),
|
||||
new HttpRequestCacheProvider(),
|
||||
new IsolatedRuntimeCache(t => new ObjectCacheRuntimeCacheProvider()))
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use the constructor the specifies all dependencies")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public CacheHelper(
|
||||
IRuntimeCacheProvider httpCacheProvider,
|
||||
ICacheProvider staticCacheProvider,
|
||||
ICacheProvider requestCacheProvider)
|
||||
: this(httpCacheProvider, staticCacheProvider, requestCacheProvider, new IsolatedRuntimeCache(t => new ObjectCacheRuntimeCacheProvider()))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance based on the provided providers
|
||||
/// </summary>
|
||||
/// <param name="httpCacheProvider"></param>
|
||||
/// <param name="staticCacheProvider"></param>
|
||||
/// <param name="requestCacheProvider"></param>
|
||||
/// <param name="isolatedCacheManager"></param>
|
||||
public CacheHelper(
|
||||
IRuntimeCacheProvider httpCacheProvider,
|
||||
ICacheProvider staticCacheProvider,
|
||||
ICacheProvider requestCacheProvider,
|
||||
IsolatedRuntimeCache isolatedCacheManager)
|
||||
{
|
||||
if (httpCacheProvider == null) throw new ArgumentNullException("httpCacheProvider");
|
||||
if (staticCacheProvider == null) throw new ArgumentNullException("staticCacheProvider");
|
||||
if (requestCacheProvider == null) throw new ArgumentNullException("requestCacheProvider");
|
||||
if (isolatedCacheManager == null) throw new ArgumentNullException("isolatedCacheManager");
|
||||
RuntimeCache = httpCacheProvider;
|
||||
StaticCache = staticCacheProvider;
|
||||
RequestCache = requestCacheProvider;
|
||||
IsolatedRuntimeCache = isolatedCacheManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current Request cache
|
||||
/// </summary>
|
||||
public ICacheProvider RequestCache { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current Runtime cache
|
||||
/// </summary>
|
||||
public ICacheProvider StaticCache { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current Runtime cache
|
||||
/// </summary>
|
||||
public IRuntimeCacheProvider RuntimeCache { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current Isolated Runtime cache manager
|
||||
/// </summary>
|
||||
public IsolatedRuntimeCache IsolatedRuntimeCache { get; internal set; }
|
||||
|
||||
#region Legacy Runtime/Http Cache accessors
|
||||
|
||||
/// <summary>
|
||||
/// Clears the item in umbraco's runtime cache
|
||||
/// </summary>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public void ClearAllCache()
|
||||
{
|
||||
RuntimeCache.ClearAllCache();
|
||||
IsolatedRuntimeCache.ClearAllCaches();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the item in umbraco's runtime cache with the given key
|
||||
/// </summary>
|
||||
/// <param name="key">Key</param>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public void ClearCacheItem(string key)
|
||||
{
|
||||
RuntimeCache.ClearCacheItem(key);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Clears all objects in the System.Web.Cache with the System.Type name as the
|
||||
/// input parameter. (using [object].GetType())
|
||||
/// </summary>
|
||||
/// <param name="typeName">The name of the System.Type which should be cleared from cache ex "System.Xml.XmlDocument"</param>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
public void ClearCacheObjectTypes(string typeName)
|
||||
{
|
||||
RuntimeCache.ClearCacheObjectTypes(typeName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all objects in the System.Web.Cache with the System.Type specified
|
||||
/// </summary>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public void ClearCacheObjectTypes<T>()
|
||||
{
|
||||
RuntimeCache.ClearCacheObjectTypes<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all cache items that starts with the key passed.
|
||||
/// </summary>
|
||||
/// <param name="keyStartsWith">The start of the key</param>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public void ClearCacheByKeySearch(string keyStartsWith)
|
||||
{
|
||||
RuntimeCache.ClearCacheByKeySearch(keyStartsWith);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all cache items that have a key that matches the regular expression
|
||||
/// </summary>
|
||||
/// <param name="regexString"></param>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public void ClearCacheByKeyExpression(string regexString)
|
||||
{
|
||||
RuntimeCache.ClearCacheByKeyExpression(regexString);
|
||||
}
|
||||
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public IEnumerable<T> GetCacheItemsByKeySearch<T>(string keyStartsWith)
|
||||
{
|
||||
return RuntimeCache.GetCacheItemsByKeySearch<T>(keyStartsWith);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a cache item by key, does not update the cache if it isn't there.
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public TT GetCacheItem<TT>(string cacheKey)
|
||||
{
|
||||
return RuntimeCache.GetCacheItem<TT>(cacheKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with all of the default parameters
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public TT GetCacheItem<TT>(string cacheKey, Func<TT> getCacheItem)
|
||||
{
|
||||
return RuntimeCache.GetCacheItem<TT>(cacheKey, getCacheItem);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public TT GetCacheItem<TT>(string cacheKey,
|
||||
TimeSpan timeout, Func<TT> getCacheItem)
|
||||
{
|
||||
return RuntimeCache.GetCacheItem<TT>(cacheKey, getCacheItem, timeout);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemRemovedCallback refreshAction, TimeSpan timeout,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
return RuntimeCache.GetCacheItem<TT>(cacheKey, getCacheItem, timeout, removedCallback: refreshAction);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemPriority priority, CacheItemRemovedCallback refreshAction, TimeSpan timeout,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
return RuntimeCache.GetCacheItem<TT>(cacheKey, getCacheItem, timeout, false, priority, refreshAction);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Do not use this method, we no longer support the caching overloads with references to CacheDependency, use the overloads specifying a file collection instead")]
|
||||
public TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
CacheItemRemovedCallback refreshAction,
|
||||
CacheDependency cacheDependency,
|
||||
TimeSpan timeout,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
|
||||
if (cache != null)
|
||||
{
|
||||
var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency);
|
||||
return result == null ? default(TT) : result.TryConvertTo<TT>().Result;
|
||||
}
|
||||
throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Do not use this method, we no longer support the caching overloads with references to CacheDependency, use the overloads specifying a file collection instead")]
|
||||
public TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
CacheDependency cacheDependency,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
|
||||
if (cache != null)
|
||||
{
|
||||
var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), null, false, priority, null, cacheDependency);
|
||||
return result == null ? default(TT) : result.TryConvertTo<TT>().Result;
|
||||
}
|
||||
throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public void InsertCacheItem<T>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
RuntimeCache.InsertCacheItem<T>(cacheKey, getCacheItem, priority: priority);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public void InsertCacheItem<T>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
TimeSpan timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
RuntimeCache.InsertCacheItem<T>(cacheKey, getCacheItem, timeout, priority: priority);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
[Obsolete("Do not use this method, we no longer support the caching overloads with references to CacheDependency, use the overloads specifying a file collection instead")]
|
||||
public void InsertCacheItem<T>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
CacheDependency cacheDependency,
|
||||
TimeSpan timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
|
||||
if (cache != null)
|
||||
{
|
||||
cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, null, cacheDependency);
|
||||
}
|
||||
throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
[Obsolete("Do not use this method, we no longer support the caching overloads with references to CacheDependency, use the overloads specifying a file collection instead")]
|
||||
public void InsertCacheItem<T>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
CacheItemRemovedCallback refreshAction,
|
||||
CacheDependency cacheDependency,
|
||||
TimeSpan? timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
|
||||
if (cache != null)
|
||||
{
|
||||
cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency);
|
||||
}
|
||||
throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider));
|
||||
}
|
||||
#endregion
|
||||
|
||||
private HttpRuntimeCacheProvider GetHttpRuntimeCacheProvider(IRuntimeCacheProvider runtimeCache)
|
||||
{
|
||||
HttpRuntimeCacheProvider cache;
|
||||
var wrapper = RuntimeCache as IRuntimeCacheProviderWrapper;
|
||||
if (wrapper != null)
|
||||
{
|
||||
cache = wrapper.InnerProvider as HttpRuntimeCacheProvider;
|
||||
}
|
||||
else
|
||||
{
|
||||
cache = RuntimeCache as HttpRuntimeCacheProvider;
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Web;
|
||||
using System.Web.Caching;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// Class that is exposed by the ApplicationContext for application wide caching purposes
|
||||
/// </summary>
|
||||
public class CacheHelper
|
||||
{
|
||||
private static readonly ICacheProvider NullRequestCache = new NullCacheProvider();
|
||||
private static readonly ICacheProvider NullStaticCache = new NullCacheProvider();
|
||||
private static readonly IRuntimeCacheProvider NullRuntimeCache = new NullCacheProvider();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a cache helper with disabled caches
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// Good for unit testing
|
||||
/// </remarks>
|
||||
public static CacheHelper CreateDisabledCacheHelper()
|
||||
{
|
||||
return new CacheHelper(NullRuntimeCache, NullStaticCache, NullRequestCache, new IsolatedRuntimeCache(t => NullRuntimeCache));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance for use in the web
|
||||
/// </summary>
|
||||
public CacheHelper()
|
||||
: this(
|
||||
new HttpRuntimeCacheProvider(HttpRuntime.Cache),
|
||||
new StaticCacheProvider(),
|
||||
new HttpRequestCacheProvider(),
|
||||
new IsolatedRuntimeCache(t => new ObjectCacheRuntimeCacheProvider()))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance for use in the web
|
||||
/// </summary>
|
||||
/// <param name="cache"></param>
|
||||
public CacheHelper(System.Web.Caching.Cache cache)
|
||||
: this(
|
||||
new HttpRuntimeCacheProvider(cache),
|
||||
new StaticCacheProvider(),
|
||||
new HttpRequestCacheProvider(),
|
||||
new IsolatedRuntimeCache(t => new ObjectCacheRuntimeCacheProvider()))
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use the constructor the specifies all dependencies")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public CacheHelper(
|
||||
IRuntimeCacheProvider httpCacheProvider,
|
||||
ICacheProvider staticCacheProvider,
|
||||
ICacheProvider requestCacheProvider)
|
||||
: this(httpCacheProvider, staticCacheProvider, requestCacheProvider, new IsolatedRuntimeCache(t => new ObjectCacheRuntimeCacheProvider()))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance based on the provided providers
|
||||
/// </summary>
|
||||
/// <param name="httpCacheProvider"></param>
|
||||
/// <param name="staticCacheProvider"></param>
|
||||
/// <param name="requestCacheProvider"></param>
|
||||
/// <param name="isolatedCacheManager"></param>
|
||||
public CacheHelper(
|
||||
IRuntimeCacheProvider httpCacheProvider,
|
||||
ICacheProvider staticCacheProvider,
|
||||
ICacheProvider requestCacheProvider,
|
||||
IsolatedRuntimeCache isolatedCacheManager)
|
||||
{
|
||||
if (httpCacheProvider == null) throw new ArgumentNullException("httpCacheProvider");
|
||||
if (staticCacheProvider == null) throw new ArgumentNullException("staticCacheProvider");
|
||||
if (requestCacheProvider == null) throw new ArgumentNullException("requestCacheProvider");
|
||||
if (isolatedCacheManager == null) throw new ArgumentNullException("isolatedCacheManager");
|
||||
RuntimeCache = httpCacheProvider;
|
||||
StaticCache = staticCacheProvider;
|
||||
RequestCache = requestCacheProvider;
|
||||
IsolatedRuntimeCache = isolatedCacheManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current Request cache
|
||||
/// </summary>
|
||||
public ICacheProvider RequestCache { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current Runtime cache
|
||||
/// </summary>
|
||||
public ICacheProvider StaticCache { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current Runtime cache
|
||||
/// </summary>
|
||||
public IRuntimeCacheProvider RuntimeCache { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current Isolated Runtime cache manager
|
||||
/// </summary>
|
||||
public IsolatedRuntimeCache IsolatedRuntimeCache { get; internal set; }
|
||||
|
||||
#region Legacy Runtime/Http Cache accessors
|
||||
|
||||
/// <summary>
|
||||
/// Clears the item in umbraco's runtime cache
|
||||
/// </summary>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public void ClearAllCache()
|
||||
{
|
||||
RuntimeCache.ClearAllCache();
|
||||
IsolatedRuntimeCache.ClearAllCaches();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the item in umbraco's runtime cache with the given key
|
||||
/// </summary>
|
||||
/// <param name="key">Key</param>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public void ClearCacheItem(string key)
|
||||
{
|
||||
RuntimeCache.ClearCacheItem(key);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Clears all objects in the System.Web.Cache with the System.Type name as the
|
||||
/// input parameter. (using [object].GetType())
|
||||
/// </summary>
|
||||
/// <param name="typeName">The name of the System.Type which should be cleared from cache ex "System.Xml.XmlDocument"</param>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
public void ClearCacheObjectTypes(string typeName)
|
||||
{
|
||||
RuntimeCache.ClearCacheObjectTypes(typeName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all objects in the System.Web.Cache with the System.Type specified
|
||||
/// </summary>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public void ClearCacheObjectTypes<T>()
|
||||
{
|
||||
RuntimeCache.ClearCacheObjectTypes<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all cache items that starts with the key passed.
|
||||
/// </summary>
|
||||
/// <param name="keyStartsWith">The start of the key</param>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public void ClearCacheByKeySearch(string keyStartsWith)
|
||||
{
|
||||
RuntimeCache.ClearCacheByKeySearch(keyStartsWith);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all cache items that have a key that matches the regular expression
|
||||
/// </summary>
|
||||
/// <param name="regexString"></param>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public void ClearCacheByKeyExpression(string regexString)
|
||||
{
|
||||
RuntimeCache.ClearCacheByKeyExpression(regexString);
|
||||
}
|
||||
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public IEnumerable<T> GetCacheItemsByKeySearch<T>(string keyStartsWith)
|
||||
{
|
||||
return RuntimeCache.GetCacheItemsByKeySearch<T>(keyStartsWith);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a cache item by key, does not update the cache if it isn't there.
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public TT GetCacheItem<TT>(string cacheKey)
|
||||
{
|
||||
return RuntimeCache.GetCacheItem<TT>(cacheKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with all of the default parameters
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public TT GetCacheItem<TT>(string cacheKey, Func<TT> getCacheItem)
|
||||
{
|
||||
return RuntimeCache.GetCacheItem<TT>(cacheKey, getCacheItem);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public TT GetCacheItem<TT>(string cacheKey,
|
||||
TimeSpan timeout, Func<TT> getCacheItem)
|
||||
{
|
||||
return RuntimeCache.GetCacheItem<TT>(cacheKey, getCacheItem, timeout);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemRemovedCallback refreshAction, TimeSpan timeout,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
return RuntimeCache.GetCacheItem<TT>(cacheKey, getCacheItem, timeout, removedCallback: refreshAction);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemPriority priority, CacheItemRemovedCallback refreshAction, TimeSpan timeout,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
return RuntimeCache.GetCacheItem<TT>(cacheKey, getCacheItem, timeout, false, priority, refreshAction);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Do not use this method, we no longer support the caching overloads with references to CacheDependency, use the overloads specifying a file collection instead")]
|
||||
public TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
CacheItemRemovedCallback refreshAction,
|
||||
CacheDependency cacheDependency,
|
||||
TimeSpan timeout,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
|
||||
if (cache != null)
|
||||
{
|
||||
var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency);
|
||||
return result == null ? default(TT) : result.TryConvertTo<TT>().Result;
|
||||
}
|
||||
throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete("Do not use this method, we no longer support the caching overloads with references to CacheDependency, use the overloads specifying a file collection instead")]
|
||||
public TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
CacheDependency cacheDependency,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
|
||||
if (cache != null)
|
||||
{
|
||||
var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), null, false, priority, null, cacheDependency);
|
||||
return result == null ? default(TT) : result.TryConvertTo<TT>().Result;
|
||||
}
|
||||
throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public void InsertCacheItem<T>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
RuntimeCache.InsertCacheItem<T>(cacheKey, getCacheItem, priority: priority);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public void InsertCacheItem<T>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
TimeSpan timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
RuntimeCache.InsertCacheItem<T>(cacheKey, getCacheItem, timeout, priority: priority);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
[Obsolete("Do not use this method, we no longer support the caching overloads with references to CacheDependency, use the overloads specifying a file collection instead")]
|
||||
public void InsertCacheItem<T>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
CacheDependency cacheDependency,
|
||||
TimeSpan timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
|
||||
if (cache != null)
|
||||
{
|
||||
cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, null, cacheDependency);
|
||||
}
|
||||
throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
[Obsolete("Do not use this method, we no longer support the caching overloads with references to CacheDependency, use the overloads specifying a file collection instead")]
|
||||
public void InsertCacheItem<T>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
CacheItemRemovedCallback refreshAction,
|
||||
CacheDependency cacheDependency,
|
||||
TimeSpan? timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
|
||||
if (cache != null)
|
||||
{
|
||||
cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency);
|
||||
}
|
||||
throw new InvalidOperationException("Cannot use this obsoleted overload when the current provider is not of type " + typeof(HttpRuntimeCacheProvider));
|
||||
}
|
||||
#endregion
|
||||
|
||||
private HttpRuntimeCacheProvider GetHttpRuntimeCacheProvider(IRuntimeCacheProvider runtimeCache)
|
||||
{
|
||||
HttpRuntimeCacheProvider cache;
|
||||
var wrapper = RuntimeCache as IRuntimeCacheProviderWrapper;
|
||||
if (wrapper != null)
|
||||
{
|
||||
cache = wrapper.InnerProvider as HttpRuntimeCacheProvider;
|
||||
}
|
||||
else
|
||||
{
|
||||
cache = RuntimeCache as HttpRuntimeCacheProvider;
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,46 +1,45 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LightInject;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using Umbraco.Core.Cache;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A resolver to return all ICacheRefresher objects
|
||||
/// </summary>
|
||||
internal sealed class CacheRefreshersResolver : ContainerLazyManyObjectsResolver<CacheRefreshersResolver, ICacheRefresher>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="serviceContainer"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="refreshers"></param>
|
||||
internal CacheRefreshersResolver(IServiceContainer serviceContainer, ILogger logger, Func<IEnumerable<Type>> refreshers)
|
||||
: base(serviceContainer, logger, refreshers)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="ICacheRefresher"/> implementations.
|
||||
/// </summary>
|
||||
public IEnumerable<ICacheRefresher> CacheRefreshers => Values;
|
||||
|
||||
/// <summary>
|
||||
/// Returns an instance for the type identified by its unique type identifier.
|
||||
/// </summary>
|
||||
/// <param name="id">The type identifier.</param>
|
||||
/// <returns>The value of the type uniquely identified by <paramref name="id"/>.</returns>
|
||||
public ICacheRefresher GetById(Guid id)
|
||||
{
|
||||
return Values.FirstOrDefault(x => x.UniqueIdentifier == id);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LightInject;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A resolver to return all ICacheRefresher objects
|
||||
/// </summary>
|
||||
internal sealed class CacheRefreshersResolver : ContainerLazyManyObjectsResolver<CacheRefreshersResolver, ICacheRefresher>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="serviceContainer"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="refreshers"></param>
|
||||
internal CacheRefreshersResolver(IServiceContainer serviceContainer, ILogger logger, Func<IEnumerable<Type>> refreshers)
|
||||
: base(serviceContainer, logger, refreshers)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="ICacheRefresher"/> implementations.
|
||||
/// </summary>
|
||||
public IEnumerable<ICacheRefresher> CacheRefreshers => Values;
|
||||
|
||||
/// <summary>
|
||||
/// Returns an instance for the type identified by its unique type identifier.
|
||||
/// </summary>
|
||||
/// <param name="id">The type identifier.</param>
|
||||
/// <returns>The value of the type uniquely identified by <paramref name="id"/>.</returns>
|
||||
public ICacheRefresher GetById(Guid id)
|
||||
{
|
||||
return Values.FirstOrDefault(x => x.UniqueIdentifier == id);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Umbraco.Core.Plugins;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
|
||||
@@ -8,6 +8,7 @@ using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Web.Caching;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Plugins;
|
||||
using CacheItemPriority = System.Web.Caching.CacheItemPriority;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
|
||||
@@ -1,167 +1,167 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A thread-safe representation of a <see cref="HashSet{T}"/>.
|
||||
/// Enumerating this collection is thread-safe and will only operate on a clone that is generated before returning the enumerator.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
[Serializable]
|
||||
public class ConcurrentHashSet<T> : ICollection<T>
|
||||
{
|
||||
private readonly HashSet<T> _innerSet = new HashSet<T>();
|
||||
private readonly ReaderWriterLockSlim _instanceLocker = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through the collection.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
|
||||
/// </returns>
|
||||
/// <filterpriority>1</filterpriority>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return GetThreadSafeClone().GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through a collection.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
|
||||
/// </returns>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the first occurrence of a specific object from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true if <paramref name="item"/> was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false. This method also returns false if <paramref name="item"/> is not found in the original <see cref="T:System.Collections.Generic.ICollection`1"/>.
|
||||
/// </returns>
|
||||
/// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception>
|
||||
public bool Remove(T item)
|
||||
{
|
||||
using (new WriteLock(_instanceLocker))
|
||||
{
|
||||
return _innerSet.Remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of elements contained in the <see cref="T:System.Collections.ICollection"/>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The number of elements contained in the <see cref="T:System.Collections.ICollection"/>.
|
||||
/// </returns>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
public int Count
|
||||
{
|
||||
get { return GetThreadSafeClone().Count; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true if the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only; otherwise, false.
|
||||
/// </returns>
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an item to the <see cref="T:System.Collections.Generic.ICollection`1"/>.
|
||||
/// </summary>
|
||||
/// <param name="item">The object to add to the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception>
|
||||
public void Add(T item)
|
||||
{
|
||||
using (new WriteLock(_instanceLocker))
|
||||
{
|
||||
_innerSet.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to add an item to the collection
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
public bool TryAdd(T item)
|
||||
{
|
||||
var clone = GetThreadSafeClone();
|
||||
if (clone.Contains(item)) return false;
|
||||
using (new WriteLock(_instanceLocker))
|
||||
{
|
||||
//double check
|
||||
if (_innerSet.Contains(item)) return false;
|
||||
_innerSet.Add(item);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all items from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
|
||||
/// </summary>
|
||||
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only. </exception>
|
||||
public void Clear()
|
||||
{
|
||||
using (new WriteLock(_instanceLocker))
|
||||
{
|
||||
_innerSet.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the <see cref="T:System.Collections.Generic.ICollection`1"/> contains a specific value.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true if <paramref name="item"/> is found in the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false.
|
||||
/// </returns>
|
||||
/// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param>
|
||||
public bool Contains(T item)
|
||||
{
|
||||
return GetThreadSafeClone().Contains(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the elements of the <see cref="T:System.Collections.Concurrent.IProducerConsumerCollection`1"/> to an <see cref="T:System.Array"/>, starting at a specified index.
|
||||
/// </summary>
|
||||
/// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the elements copied from the <see cref="T:System.Collections.Concurrent.IProducerConsumerCollection`1"/>. The array must have zero-based indexing.</param><param name="index">The zero-based index in <paramref name="array"/> at which copying begins.</param><exception cref="T:System.ArgumentNullException"><paramref name="array"/> is a null reference (Nothing in Visual Basic).</exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is less than zero.</exception><exception cref="T:System.ArgumentException"><paramref name="index"/> is equal to or greater than the length of the <paramref name="array"/> -or- The number of elements in the source <see cref="T:System.Collections.Concurrent.ConcurrentQueue`1"/> is greater than the available space from <paramref name="index"/> to the end of the destination <paramref name="array"/>.</exception>
|
||||
public void CopyTo(T[] array, int index)
|
||||
{
|
||||
var clone = GetThreadSafeClone();
|
||||
clone.CopyTo(array, index);
|
||||
}
|
||||
|
||||
private HashSet<T> GetThreadSafeClone()
|
||||
{
|
||||
HashSet<T> clone = null;
|
||||
using (new WriteLock(_instanceLocker))
|
||||
{
|
||||
clone = new HashSet<T>(_innerSet, _innerSet.Comparer);
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the elements of the <see cref="T:System.Collections.ICollection"/> to an <see cref="T:System.Array"/>, starting at a particular <see cref="T:System.Array"/> index.
|
||||
/// </summary>
|
||||
/// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the elements copied from <see cref="T:System.Collections.ICollection"/>. The <see cref="T:System.Array"/> must have zero-based indexing. </param><param name="index">The zero-based index in <paramref name="array"/> at which copying begins. </param><exception cref="T:System.ArgumentNullException"><paramref name="array"/> is null. </exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is less than zero. </exception><exception cref="T:System.ArgumentException"><paramref name="array"/> is multidimensional.-or- The number of elements in the source <see cref="T:System.Collections.ICollection"/> is greater than the available space from <paramref name="index"/> to the end of the destination <paramref name="array"/>. </exception><exception cref="T:System.ArgumentException">The type of the source <see cref="T:System.Collections.ICollection"/> cannot be cast automatically to the type of the destination <paramref name="array"/>. </exception><filterpriority>2</filterpriority>
|
||||
public void CopyTo(Array array, int index)
|
||||
{
|
||||
var clone = GetThreadSafeClone();
|
||||
Array.Copy(clone.ToArray(), 0, array, index, clone.Count);
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace Umbraco.Core.Collections
|
||||
{
|
||||
/// <summary>
|
||||
/// A thread-safe representation of a <see cref="HashSet{T}"/>.
|
||||
/// Enumerating this collection is thread-safe and will only operate on a clone that is generated before returning the enumerator.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
[Serializable]
|
||||
public class ConcurrentHashSet<T> : ICollection<T>
|
||||
{
|
||||
private readonly HashSet<T> _innerSet = new HashSet<T>();
|
||||
private readonly ReaderWriterLockSlim _instanceLocker = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through the collection.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
|
||||
/// </returns>
|
||||
/// <filterpriority>1</filterpriority>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return GetThreadSafeClone().GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through a collection.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
|
||||
/// </returns>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the first occurrence of a specific object from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true if <paramref name="item"/> was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false. This method also returns false if <paramref name="item"/> is not found in the original <see cref="T:System.Collections.Generic.ICollection`1"/>.
|
||||
/// </returns>
|
||||
/// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception>
|
||||
public bool Remove(T item)
|
||||
{
|
||||
using (new WriteLock(_instanceLocker))
|
||||
{
|
||||
return _innerSet.Remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of elements contained in the <see cref="T:System.Collections.ICollection"/>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The number of elements contained in the <see cref="T:System.Collections.ICollection"/>.
|
||||
/// </returns>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
public int Count
|
||||
{
|
||||
get { return GetThreadSafeClone().Count; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true if the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only; otherwise, false.
|
||||
/// </returns>
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an item to the <see cref="T:System.Collections.Generic.ICollection`1"/>.
|
||||
/// </summary>
|
||||
/// <param name="item">The object to add to the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception>
|
||||
public void Add(T item)
|
||||
{
|
||||
using (new WriteLock(_instanceLocker))
|
||||
{
|
||||
_innerSet.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to add an item to the collection
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
public bool TryAdd(T item)
|
||||
{
|
||||
var clone = GetThreadSafeClone();
|
||||
if (clone.Contains(item)) return false;
|
||||
using (new WriteLock(_instanceLocker))
|
||||
{
|
||||
//double check
|
||||
if (_innerSet.Contains(item)) return false;
|
||||
_innerSet.Add(item);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all items from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
|
||||
/// </summary>
|
||||
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only. </exception>
|
||||
public void Clear()
|
||||
{
|
||||
using (new WriteLock(_instanceLocker))
|
||||
{
|
||||
_innerSet.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the <see cref="T:System.Collections.Generic.ICollection`1"/> contains a specific value.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true if <paramref name="item"/> is found in the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false.
|
||||
/// </returns>
|
||||
/// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param>
|
||||
public bool Contains(T item)
|
||||
{
|
||||
return GetThreadSafeClone().Contains(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the elements of the <see cref="T:System.Collections.Concurrent.IProducerConsumerCollection`1"/> to an <see cref="T:System.Array"/>, starting at a specified index.
|
||||
/// </summary>
|
||||
/// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the elements copied from the <see cref="T:System.Collections.Concurrent.IProducerConsumerCollection`1"/>. The array must have zero-based indexing.</param><param name="index">The zero-based index in <paramref name="array"/> at which copying begins.</param><exception cref="T:System.ArgumentNullException"><paramref name="array"/> is a null reference (Nothing in Visual Basic).</exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is less than zero.</exception><exception cref="T:System.ArgumentException"><paramref name="index"/> is equal to or greater than the length of the <paramref name="array"/> -or- The number of elements in the source <see cref="T:System.Collections.Concurrent.ConcurrentQueue`1"/> is greater than the available space from <paramref name="index"/> to the end of the destination <paramref name="array"/>.</exception>
|
||||
public void CopyTo(T[] array, int index)
|
||||
{
|
||||
var clone = GetThreadSafeClone();
|
||||
clone.CopyTo(array, index);
|
||||
}
|
||||
|
||||
private HashSet<T> GetThreadSafeClone()
|
||||
{
|
||||
HashSet<T> clone = null;
|
||||
using (new WriteLock(_instanceLocker))
|
||||
{
|
||||
clone = new HashSet<T>(_innerSet, _innerSet.Comparer);
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the elements of the <see cref="T:System.Collections.ICollection"/> to an <see cref="T:System.Array"/>, starting at a particular <see cref="T:System.Array"/> index.
|
||||
/// </summary>
|
||||
/// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the elements copied from <see cref="T:System.Collections.ICollection"/>. The <see cref="T:System.Array"/> must have zero-based indexing. </param><param name="index">The zero-based index in <paramref name="array"/> at which copying begins. </param><exception cref="T:System.ArgumentNullException"><paramref name="array"/> is null. </exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is less than zero. </exception><exception cref="T:System.ArgumentException"><paramref name="array"/> is multidimensional.-or- The number of elements in the source <see cref="T:System.Collections.ICollection"/> is greater than the available space from <paramref name="index"/> to the end of the destination <paramref name="array"/>. </exception><exception cref="T:System.ArgumentException">The type of the source <see cref="T:System.Collections.ICollection"/> cannot be cast automatically to the type of the destination <paramref name="array"/>. </exception><filterpriority>2</filterpriority>
|
||||
public void CopyTo(Array array, int index)
|
||||
{
|
||||
var clone = GetThreadSafeClone();
|
||||
Array.Copy(clone.ToArray(), 0, array, index, clone.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,172 +1,170 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// An ObservableDictionary
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Assumes that the key will not change and is unique for each element in the collection.
|
||||
/// Collection is not thread-safe, so calls should be made single-threaded.
|
||||
/// </remarks>
|
||||
/// <typeparam name="TValue">The type of elements contained in the BindableCollection</typeparam>
|
||||
/// <typeparam name="TKey">The type of the indexing key</typeparam>
|
||||
public class ObservableDictionary<TKey, TValue> : ObservableCollection<TValue>
|
||||
{
|
||||
protected Dictionary<TKey, int> Indecies = new Dictionary<TKey, int>();
|
||||
protected Func<TValue, TKey> KeySelector;
|
||||
|
||||
/// <summary>
|
||||
/// Create new ObservableDictionary
|
||||
/// </summary>
|
||||
/// <param name="keySelector">Selector function to create key from value</param>
|
||||
public ObservableDictionary(Func<TValue, TKey> keySelector)
|
||||
: base()
|
||||
{
|
||||
if (keySelector == null) throw new ArgumentException("keySelector");
|
||||
KeySelector = keySelector;
|
||||
}
|
||||
|
||||
#region Protected Methods
|
||||
protected override void InsertItem(int index, TValue item)
|
||||
{
|
||||
var key = KeySelector(item);
|
||||
if (Indecies.ContainsKey(key))
|
||||
throw new DuplicateKeyException(key.ToString());
|
||||
|
||||
if (index != this.Count)
|
||||
{
|
||||
foreach (var k in Indecies.Keys.Where(k => Indecies[k] >= index).ToList())
|
||||
{
|
||||
Indecies[k]++;
|
||||
}
|
||||
}
|
||||
|
||||
base.InsertItem(index, item);
|
||||
Indecies[key] = index;
|
||||
|
||||
}
|
||||
|
||||
protected override void ClearItems()
|
||||
{
|
||||
base.ClearItems();
|
||||
Indecies.Clear();
|
||||
}
|
||||
|
||||
|
||||
protected override void RemoveItem(int index)
|
||||
{
|
||||
var item = this[index];
|
||||
var key = KeySelector(item);
|
||||
|
||||
base.RemoveItem(index);
|
||||
|
||||
Indecies.Remove(key);
|
||||
|
||||
foreach (var k in Indecies.Keys.Where(k => Indecies[k] > index).ToList())
|
||||
{
|
||||
Indecies[k]--;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public virtual bool ContainsKey(TKey key)
|
||||
{
|
||||
return Indecies.ContainsKey(key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the element with the specified key. If setting a new value, new value must have same key.
|
||||
/// </summary>
|
||||
/// <param name="key">Key of element to replace</param>
|
||||
/// <returns></returns>
|
||||
public virtual TValue this[TKey key]
|
||||
{
|
||||
|
||||
get { return this[Indecies[key]]; }
|
||||
set
|
||||
{
|
||||
//confirm key matches
|
||||
if (!KeySelector(value).Equals(key))
|
||||
throw new InvalidOperationException("Key of new value does not match");
|
||||
|
||||
if (!Indecies.ContainsKey(key))
|
||||
{
|
||||
this.Add(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
this[Indecies[key]] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces element at given key with new value. New value must have same key.
|
||||
/// </summary>
|
||||
/// <param name="key">Key of element to replace</param>
|
||||
/// <param name="value">New value</param>
|
||||
///
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
/// <returns>False if key not found</returns>
|
||||
public virtual bool Replace(TKey key, TValue value)
|
||||
{
|
||||
if (!Indecies.ContainsKey(key)) return false;
|
||||
//confirm key matches
|
||||
if (!KeySelector(value).Equals(key))
|
||||
throw new InvalidOperationException("Key of new value does not match");
|
||||
|
||||
this[Indecies[key]] = value;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public virtual bool Remove(TKey key)
|
||||
{
|
||||
if (!Indecies.ContainsKey(key)) return false;
|
||||
|
||||
this.RemoveAt(Indecies[key]);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows us to change the key of an item
|
||||
/// </summary>
|
||||
/// <param name="currentKey"></param>
|
||||
/// <param name="newKey"></param>
|
||||
public virtual void ChangeKey(TKey currentKey, TKey newKey)
|
||||
{
|
||||
if (!Indecies.ContainsKey(currentKey))
|
||||
{
|
||||
throw new InvalidOperationException("No item with the key " + currentKey + "was found in the collection");
|
||||
}
|
||||
if (ContainsKey(newKey))
|
||||
{
|
||||
throw new DuplicateKeyException(newKey.ToString());
|
||||
}
|
||||
|
||||
var currentIndex = Indecies[currentKey];
|
||||
|
||||
Indecies.Remove(currentKey);
|
||||
Indecies.Add(newKey, currentIndex);
|
||||
}
|
||||
|
||||
internal class DuplicateKeyException : Exception
|
||||
{
|
||||
|
||||
public string Key { get; private set; }
|
||||
public DuplicateKeyException(string key)
|
||||
: base("Attempted to insert duplicate key " + key + " in collection")
|
||||
{
|
||||
Key = key;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Collections
|
||||
{
|
||||
/// <summary>
|
||||
/// An ObservableDictionary
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Assumes that the key will not change and is unique for each element in the collection.
|
||||
/// Collection is not thread-safe, so calls should be made single-threaded.
|
||||
/// </remarks>
|
||||
/// <typeparam name="TValue">The type of elements contained in the BindableCollection</typeparam>
|
||||
/// <typeparam name="TKey">The type of the indexing key</typeparam>
|
||||
public class ObservableDictionary<TKey, TValue> : ObservableCollection<TValue>
|
||||
{
|
||||
protected Dictionary<TKey, int> Indecies = new Dictionary<TKey, int>();
|
||||
protected Func<TValue, TKey> KeySelector;
|
||||
|
||||
/// <summary>
|
||||
/// Create new ObservableDictionary
|
||||
/// </summary>
|
||||
/// <param name="keySelector">Selector function to create key from value</param>
|
||||
public ObservableDictionary(Func<TValue, TKey> keySelector)
|
||||
: base()
|
||||
{
|
||||
if (keySelector == null) throw new ArgumentException("keySelector");
|
||||
KeySelector = keySelector;
|
||||
}
|
||||
|
||||
#region Protected Methods
|
||||
protected override void InsertItem(int index, TValue item)
|
||||
{
|
||||
var key = KeySelector(item);
|
||||
if (Indecies.ContainsKey(key))
|
||||
throw new DuplicateKeyException(key.ToString());
|
||||
|
||||
if (index != this.Count)
|
||||
{
|
||||
foreach (var k in Indecies.Keys.Where(k => Indecies[k] >= index).ToList())
|
||||
{
|
||||
Indecies[k]++;
|
||||
}
|
||||
}
|
||||
|
||||
base.InsertItem(index, item);
|
||||
Indecies[key] = index;
|
||||
|
||||
}
|
||||
|
||||
protected override void ClearItems()
|
||||
{
|
||||
base.ClearItems();
|
||||
Indecies.Clear();
|
||||
}
|
||||
|
||||
|
||||
protected override void RemoveItem(int index)
|
||||
{
|
||||
var item = this[index];
|
||||
var key = KeySelector(item);
|
||||
|
||||
base.RemoveItem(index);
|
||||
|
||||
Indecies.Remove(key);
|
||||
|
||||
foreach (var k in Indecies.Keys.Where(k => Indecies[k] > index).ToList())
|
||||
{
|
||||
Indecies[k]--;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public virtual bool ContainsKey(TKey key)
|
||||
{
|
||||
return Indecies.ContainsKey(key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the element with the specified key. If setting a new value, new value must have same key.
|
||||
/// </summary>
|
||||
/// <param name="key">Key of element to replace</param>
|
||||
/// <returns></returns>
|
||||
public virtual TValue this[TKey key]
|
||||
{
|
||||
|
||||
get { return this[Indecies[key]]; }
|
||||
set
|
||||
{
|
||||
//confirm key matches
|
||||
if (!KeySelector(value).Equals(key))
|
||||
throw new InvalidOperationException("Key of new value does not match");
|
||||
|
||||
if (!Indecies.ContainsKey(key))
|
||||
{
|
||||
this.Add(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
this[Indecies[key]] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replaces element at given key with new value. New value must have same key.
|
||||
/// </summary>
|
||||
/// <param name="key">Key of element to replace</param>
|
||||
/// <param name="value">New value</param>
|
||||
///
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
/// <returns>False if key not found</returns>
|
||||
public virtual bool Replace(TKey key, TValue value)
|
||||
{
|
||||
if (!Indecies.ContainsKey(key)) return false;
|
||||
//confirm key matches
|
||||
if (!KeySelector(value).Equals(key))
|
||||
throw new InvalidOperationException("Key of new value does not match");
|
||||
|
||||
this[Indecies[key]] = value;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public virtual bool Remove(TKey key)
|
||||
{
|
||||
if (!Indecies.ContainsKey(key)) return false;
|
||||
|
||||
this.RemoveAt(Indecies[key]);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows us to change the key of an item
|
||||
/// </summary>
|
||||
/// <param name="currentKey"></param>
|
||||
/// <param name="newKey"></param>
|
||||
public virtual void ChangeKey(TKey currentKey, TKey newKey)
|
||||
{
|
||||
if (!Indecies.ContainsKey(currentKey))
|
||||
{
|
||||
throw new InvalidOperationException("No item with the key " + currentKey + "was found in the collection");
|
||||
}
|
||||
if (ContainsKey(newKey))
|
||||
{
|
||||
throw new DuplicateKeyException(newKey.ToString());
|
||||
}
|
||||
|
||||
var currentIndex = Indecies[currentKey];
|
||||
|
||||
Indecies.Remove(currentKey);
|
||||
Indecies.Add(newKey, currentIndex);
|
||||
}
|
||||
|
||||
internal class DuplicateKeyException : Exception
|
||||
{
|
||||
|
||||
public string Key { get; private set; }
|
||||
public DuplicateKeyException(string key)
|
||||
: base("Attempted to insert duplicate key " + key + " in collection")
|
||||
{
|
||||
Key = key;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using Umbraco.Core.Macros;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
@@ -183,19 +184,6 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
}
|
||||
}
|
||||
|
||||
[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<IconPickerBehaviour> DocumentTypeIconList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new OptionalInnerTextConfigurationElement<IconPickerBehaviour>(
|
||||
(InnerTextConfigurationElement<IconPickerBehaviour>)this["DocumentTypeIconList"],
|
||||
//set the default
|
||||
IconPickerBehaviour.HideFileDuplicates);
|
||||
}
|
||||
}
|
||||
|
||||
[ConfigurationProperty("disallowedUploadFiles")]
|
||||
internal CommaDelimitedConfigurationElement DisallowedUploadFiles
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Macros;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.Migrations;
|
||||
using Umbraco.Core.Profiling;
|
||||
using Umbraco.Core.Plugins;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Sync;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using LightInject;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence;
|
||||
@@ -6,6 +7,7 @@ using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Core.Plugins;
|
||||
|
||||
namespace Umbraco.Core.DependencyInjection
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using LightInject;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Web;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Profiling;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@ using System.IO;
|
||||
using System.Web;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Xml;
|
||||
|
||||
namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.Plugins;
|
||||
|
||||
namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@ using System.Text;
|
||||
using System.Web.Services.Description;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Plugins;
|
||||
|
||||
namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Macros;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Reflection;
|
||||
using System.Text;
|
||||
using Umbraco.Core.CodeAnnotations;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Plugins;
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
{
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
[Obsolete("This is no longer used and will be removed from the core in future versions")]
|
||||
public enum IconPickerBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Default umbraco behavior - show duplicates in files and sprites
|
||||
/// </summary>
|
||||
ShowDuplicates,
|
||||
|
||||
/// <summary>
|
||||
/// If a file exists on disk with the same name as one in the sprite
|
||||
/// then the file on disk overrules the one in the sprite, the
|
||||
/// sprite icon will not be shown
|
||||
/// </summary>
|
||||
HideSpriteDuplicates,
|
||||
|
||||
/// <summary>
|
||||
/// If a file exists on disk with the same name as one in the sprite
|
||||
/// then the file in the sprite overrules the one on disk, the file
|
||||
/// on disk will be shown
|
||||
/// </summary>
|
||||
HideFileDuplicates
|
||||
}
|
||||
}
|
||||
@@ -1,43 +1,43 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Profiling
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines an object for use in the application to profile operations
|
||||
/// </summary>
|
||||
public interface IProfiler
|
||||
{
|
||||
/// <summary>
|
||||
/// Render the UI to display the profiler
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// Generally used for HTML displays
|
||||
/// </remarks>
|
||||
string Render();
|
||||
|
||||
/// <summary>
|
||||
/// Profile an operation
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// Use the 'using(' syntax
|
||||
/// </remarks>
|
||||
IDisposable Step(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Start the profiler
|
||||
/// </summary>
|
||||
void Start();
|
||||
|
||||
/// <summary>
|
||||
/// Start the profiler
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// set discardResults to false when you want to abandon all profiling, this is useful for
|
||||
/// when someone is not authenticated or you want to clear the results based on some other mechanism.
|
||||
/// </remarks>
|
||||
void Stop(bool discardResults = false);
|
||||
}
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines an object for use in the application to profile operations
|
||||
/// </summary>
|
||||
public interface IProfiler
|
||||
{
|
||||
/// <summary>
|
||||
/// Render the UI to display the profiler
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// Generally used for HTML displays
|
||||
/// </remarks>
|
||||
string Render();
|
||||
|
||||
/// <summary>
|
||||
/// Profile an operation
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// Use the 'using(' syntax
|
||||
/// </remarks>
|
||||
IDisposable Step(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Start the profiler
|
||||
/// </summary>
|
||||
void Start();
|
||||
|
||||
/// <summary>
|
||||
/// Start the profiler
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// set discardResults to false when you want to abandon all profiling, this is useful for
|
||||
/// when someone is not authenticated or you want to clear the results based on some other mechanism.
|
||||
/// </remarks>
|
||||
void Stop(bool discardResults = false);
|
||||
}
|
||||
}
|
||||
@@ -1,42 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.Profiling
|
||||
{
|
||||
/// <summary>
|
||||
/// A profiler that outputs its results to an ILogger
|
||||
/// </summary>
|
||||
internal class LogProfiler : IProfiler
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public LogProfiler(ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public string Render()
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public IDisposable Step(string name)
|
||||
{
|
||||
_logger.Debug(typeof(LogProfiler), "Starting - " + name);
|
||||
return new DisposableTimer(l => _logger.Info(typeof(LogProfiler), () => name + " (took " + l + "ms)"));
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
//the log will alwasy be started
|
||||
}
|
||||
|
||||
public void Stop(bool discardResults = false)
|
||||
{
|
||||
//we don't need to do anything here
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// A profiler that outputs its results to an ILogger
|
||||
/// </summary>
|
||||
internal class LogProfiler : IProfiler
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public LogProfiler(ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public string Render()
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public IDisposable Step(string name)
|
||||
{
|
||||
_logger.Debug(typeof(LogProfiler), "Starting - " + name);
|
||||
return new DisposableTimer(l => _logger.Info(typeof(LogProfiler), () => name + " (took " + l + "ms)"));
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
//the log will alwasy be started
|
||||
}
|
||||
|
||||
public void Stop(bool discardResults = false)
|
||||
{
|
||||
//we don't need to do anything here
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,35 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Profiling
|
||||
{
|
||||
internal static class ProfilerExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes out a step prefixed with the type
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="profiler"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
internal static IDisposable Step<T>(this IProfiler profiler, string name)
|
||||
{
|
||||
if (profiler == null) throw new ArgumentNullException("profiler");
|
||||
return profiler.Step(typeof (T), name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes out a step prefixed with the type
|
||||
/// </summary>
|
||||
/// <param name="profiler"></param>
|
||||
/// <param name="objectType"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
internal static IDisposable Step(this IProfiler profiler, Type objectType, string name)
|
||||
{
|
||||
if (profiler == null) throw new ArgumentNullException("profiler");
|
||||
if (objectType == null) throw new ArgumentNullException("objectType");
|
||||
if (name == null) throw new ArgumentNullException("name");
|
||||
return profiler.Step(string.Format("[{0}] {1}", objectType.Name, name));
|
||||
}
|
||||
}
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
internal static class ProfilerExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes out a step prefixed with the type
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="profiler"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
internal static IDisposable Step<T>(this IProfiler profiler, string name)
|
||||
{
|
||||
if (profiler == null) throw new ArgumentNullException("profiler");
|
||||
return profiler.Step(typeof (T), name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes out a step prefixed with the type
|
||||
/// </summary>
|
||||
/// <param name="profiler"></param>
|
||||
/// <param name="objectType"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
internal static IDisposable Step(this IProfiler profiler, Type objectType, string name)
|
||||
{
|
||||
if (profiler == null) throw new ArgumentNullException("profiler");
|
||||
if (objectType == null) throw new ArgumentNullException("objectType");
|
||||
if (name == null) throw new ArgumentNullException("name");
|
||||
return profiler.Step(string.Format("[{0}] {1}", objectType.Name, name));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,42 +1,42 @@
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
|
||||
namespace Umbraco.Core.Profiling
|
||||
{
|
||||
/// <summary>
|
||||
/// A resolver exposing the current profiler
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// NOTE: This is a 'special' resolver in that it gets initialized before most other things, it cannot use IoC so it cannot implement ContainerObjectResolverBase
|
||||
/// </remarks>
|
||||
internal class ProfilerResolver : SingleObjectResolverBase<ProfilerResolver, IProfiler>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="profiler"></param>
|
||||
public ProfilerResolver(IProfiler profiler)
|
||||
: base(profiler)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method allowing to change the profiler during startup
|
||||
/// </summary>
|
||||
/// <param name="profiler"></param>
|
||||
internal void SetProfiler(IProfiler profiler)
|
||||
{
|
||||
Value = profiler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current profiler
|
||||
/// </summary>
|
||||
public IProfiler Profiler
|
||||
{
|
||||
get { return Value; }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// A resolver exposing the current profiler
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// NOTE: This is a 'special' resolver in that it gets initialized before most other things, it cannot use IoC so it cannot implement ContainerObjectResolverBase
|
||||
/// </remarks>
|
||||
internal class ProfilerResolver : SingleObjectResolverBase<ProfilerResolver, IProfiler>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="profiler"></param>
|
||||
public ProfilerResolver(IProfiler profiler)
|
||||
: base(profiler)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method allowing to change the profiler during startup
|
||||
/// </summary>
|
||||
/// <param name="profiler"></param>
|
||||
internal void SetProfiler(IProfiler profiler)
|
||||
{
|
||||
Value = profiler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current profiler
|
||||
/// </summary>
|
||||
public IProfiler Profiler
|
||||
{
|
||||
get { return Value; }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using Umbraco.Core.Profiling;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
|
||||
@@ -1,165 +1,164 @@
|
||||
using System;
|
||||
using System.Web;
|
||||
using StackExchange.Profiling;
|
||||
using StackExchange.Profiling.SqlFormatters;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.Profiling
|
||||
{
|
||||
/// <summary>
|
||||
/// A profiler used for web based activity based on the MiniProfiler framework
|
||||
/// </summary>
|
||||
internal class WebProfiler : ApplicationEventHandler, IProfiler
|
||||
{
|
||||
/// <summary>
|
||||
///Binds to application events to enable the MiniProfiler
|
||||
/// </summary>
|
||||
/// <param name="umbracoApplication"></param>
|
||||
/// <param name="applicationContext"></param>
|
||||
protected override void ApplicationInitialized(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
|
||||
{
|
||||
UmbracoApplicationBase.ApplicationInit += UmbracoApplicationApplicationInit;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Handle the Init event o fthe UmbracoApplication which allows us to subscribe to the HttpApplication events
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
void UmbracoApplicationApplicationInit(object sender, EventArgs e)
|
||||
{
|
||||
var app = sender as HttpApplication;
|
||||
if (app == null) return;
|
||||
|
||||
if (SystemUtilities.GetCurrentTrustLevel() < AspNetHostingPermissionLevel.High)
|
||||
{
|
||||
//If we don't have a high enough trust level we cannot bind to the events
|
||||
LogHelper.Info<WebProfiler>("Cannot start the WebProfiler since the application is running in Medium trust");
|
||||
}
|
||||
else
|
||||
{
|
||||
app.BeginRequest += UmbracoApplicationBeginRequest;
|
||||
app.EndRequest += UmbracoApplicationEndRequest;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle the begin request event
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
void UmbracoApplicationEndRequest(object sender, EventArgs e)
|
||||
{
|
||||
if (CanPerformProfilingAction(sender))
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle the end request event
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
void UmbracoApplicationBeginRequest(object sender, EventArgs e)
|
||||
{
|
||||
if (CanPerformProfilingAction(sender))
|
||||
{
|
||||
Start();
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanPerformProfilingAction(object sender)
|
||||
{
|
||||
if (GlobalSettings.DebugMode == false)
|
||||
return false;
|
||||
|
||||
//will not run in medium trust
|
||||
if (SystemUtilities.GetCurrentTrustLevel() < AspNetHostingPermissionLevel.High)
|
||||
return false;
|
||||
|
||||
var request = TryGetRequest(sender);
|
||||
|
||||
if (request.Success == false || request.Result.Url.IsClientSideRequest())
|
||||
return false;
|
||||
|
||||
if (string.IsNullOrEmpty(request.Result.QueryString["umbDebug"]))
|
||||
return true;
|
||||
|
||||
if (request.Result.Url.IsBackOfficeRequest(HttpRuntime.AppDomainAppVirtualPath))
|
||||
return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Render the UI to display the profiler
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// Generally used for HTML displays
|
||||
/// </remarks>
|
||||
public string Render()
|
||||
{
|
||||
return MiniProfiler.RenderIncludes(RenderPosition.Right).ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Profile a step
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// Use the 'using(' syntax
|
||||
/// </remarks>
|
||||
public IDisposable Step(string name)
|
||||
{
|
||||
return GlobalSettings.DebugMode == false ? null : MiniProfiler.Current.Step(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the profiler
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
MiniProfiler.Settings.SqlFormatter = new SqlServerFormatter();
|
||||
MiniProfiler.Settings.StackMaxLength = 5000;
|
||||
MiniProfiler.Start();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the profiler
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// set discardResults to false when you want to abandon all profiling, this is useful for
|
||||
/// when someone is not authenticated or you want to clear the results based on some other mechanism.
|
||||
/// </remarks>
|
||||
public void Stop(bool discardResults = false)
|
||||
{
|
||||
MiniProfiler.Stop(discardResults);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the request object from the app instance if it is available
|
||||
/// </summary>
|
||||
/// <param name="sender">The application object</param>
|
||||
/// <returns></returns>
|
||||
private Attempt<HttpRequestBase> TryGetRequest(object sender)
|
||||
{
|
||||
var app = sender as HttpApplication;
|
||||
if (app == null) return Attempt<HttpRequestBase>.Fail();
|
||||
|
||||
try
|
||||
{
|
||||
var req = app.Request;
|
||||
return Attempt<HttpRequestBase>.Succeed(new HttpRequestWrapper(req));
|
||||
}
|
||||
catch (HttpException ex)
|
||||
{
|
||||
return Attempt<HttpRequestBase>.Fail(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Web;
|
||||
using StackExchange.Profiling;
|
||||
using StackExchange.Profiling.SqlFormatters;
|
||||
using Umbraco.Core.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// A profiler used for web based activity based on the MiniProfiler framework
|
||||
/// </summary>
|
||||
internal class WebProfiler : ApplicationEventHandler, IProfiler
|
||||
{
|
||||
/// <summary>
|
||||
///Binds to application events to enable the MiniProfiler
|
||||
/// </summary>
|
||||
/// <param name="umbracoApplication"></param>
|
||||
/// <param name="applicationContext"></param>
|
||||
protected override void ApplicationInitialized(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
|
||||
{
|
||||
UmbracoApplicationBase.ApplicationInit += UmbracoApplicationApplicationInit;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Handle the Init event o fthe UmbracoApplication which allows us to subscribe to the HttpApplication events
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
void UmbracoApplicationApplicationInit(object sender, EventArgs e)
|
||||
{
|
||||
var app = sender as HttpApplication;
|
||||
if (app == null) return;
|
||||
|
||||
if (SystemUtilities.GetCurrentTrustLevel() < AspNetHostingPermissionLevel.High)
|
||||
{
|
||||
//If we don't have a high enough trust level we cannot bind to the events
|
||||
LogHelper.Info<WebProfiler>("Cannot start the WebProfiler since the application is running in Medium trust");
|
||||
}
|
||||
else
|
||||
{
|
||||
app.BeginRequest += UmbracoApplicationBeginRequest;
|
||||
app.EndRequest += UmbracoApplicationEndRequest;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle the begin request event
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
void UmbracoApplicationEndRequest(object sender, EventArgs e)
|
||||
{
|
||||
if (CanPerformProfilingAction(sender))
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle the end request event
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
void UmbracoApplicationBeginRequest(object sender, EventArgs e)
|
||||
{
|
||||
if (CanPerformProfilingAction(sender))
|
||||
{
|
||||
Start();
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanPerformProfilingAction(object sender)
|
||||
{
|
||||
if (GlobalSettings.DebugMode == false)
|
||||
return false;
|
||||
|
||||
//will not run in medium trust
|
||||
if (SystemUtilities.GetCurrentTrustLevel() < AspNetHostingPermissionLevel.High)
|
||||
return false;
|
||||
|
||||
var request = TryGetRequest(sender);
|
||||
|
||||
if (request.Success == false || request.Result.Url.IsClientSideRequest())
|
||||
return false;
|
||||
|
||||
if (string.IsNullOrEmpty(request.Result.QueryString["umbDebug"]))
|
||||
return true;
|
||||
|
||||
if (request.Result.Url.IsBackOfficeRequest(HttpRuntime.AppDomainAppVirtualPath))
|
||||
return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Render the UI to display the profiler
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// Generally used for HTML displays
|
||||
/// </remarks>
|
||||
public string Render()
|
||||
{
|
||||
return MiniProfiler.RenderIncludes(RenderPosition.Right).ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Profile a step
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// Use the 'using(' syntax
|
||||
/// </remarks>
|
||||
public IDisposable Step(string name)
|
||||
{
|
||||
return GlobalSettings.DebugMode == false ? null : MiniProfiler.Current.Step(name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the profiler
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
MiniProfiler.Settings.SqlFormatter = new SqlServerFormatter();
|
||||
MiniProfiler.Settings.StackMaxLength = 5000;
|
||||
MiniProfiler.Start();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the profiler
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// set discardResults to false when you want to abandon all profiling, this is useful for
|
||||
/// when someone is not authenticated or you want to clear the results based on some other mechanism.
|
||||
/// </remarks>
|
||||
public void Stop(bool discardResults = false)
|
||||
{
|
||||
MiniProfiler.Stop(discardResults);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the request object from the app instance if it is available
|
||||
/// </summary>
|
||||
/// <param name="sender">The application object</param>
|
||||
/// <returns></returns>
|
||||
private Attempt<HttpRequestBase> TryGetRequest(object sender)
|
||||
{
|
||||
var app = sender as HttpApplication;
|
||||
if (app == null) return Attempt<HttpRequestBase>.Fail();
|
||||
|
||||
try
|
||||
{
|
||||
var req = app.Request;
|
||||
return Attempt<HttpRequestBase>.Succeed(new HttpRequestWrapper(req));
|
||||
}
|
||||
catch (HttpException ex)
|
||||
{
|
||||
return Attempt<HttpRequestBase>.Fail(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,23 @@
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public enum MacroErrorBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Default umbraco behavior - show an inline error within the
|
||||
/// macro but allow the page to continue rendering.
|
||||
/// </summary>
|
||||
Inline,
|
||||
|
||||
/// <summary>
|
||||
/// Silently eat the error and do not display the offending macro.
|
||||
/// </summary>
|
||||
Silent,
|
||||
|
||||
/// <summary>
|
||||
/// Throw an exception which can be caught by the global error handler
|
||||
/// defined in Application_OnError. If no such error handler is defined
|
||||
/// then you'll see the Yellow Screen Of Death (YSOD) error page.
|
||||
/// </summary>
|
||||
Throw
|
||||
}
|
||||
}
|
||||
namespace Umbraco.Core.Macros
|
||||
{
|
||||
public enum MacroErrorBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Default umbraco behavior - show an inline error within the
|
||||
/// macro but allow the page to continue rendering.
|
||||
/// </summary>
|
||||
Inline,
|
||||
|
||||
/// <summary>
|
||||
/// Silently eat the error and do not display the offending macro.
|
||||
/// </summary>
|
||||
Silent,
|
||||
|
||||
/// <summary>
|
||||
/// Throw an exception which can be caught by the global error handler
|
||||
/// defined in Application_OnError. If no such error handler is defined
|
||||
/// then you'll see the Yellow Screen Of Death (YSOD) error page.
|
||||
/// </summary>
|
||||
Throw
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using HtmlAgilityPack;
|
||||
using Umbraco.Core.Xml;
|
||||
|
||||
namespace Umbraco.Core.Macros
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Umbraco.Core.Plugins;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Plugins;
|
||||
|
||||
namespace Umbraco.Core.Models.EntityBase
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Collections;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Xml.Linq;
|
||||
using System.Xml.XPath;
|
||||
using Umbraco.Core.Dynamics;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Xml;
|
||||
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Xml;
|
||||
using Umbraco.Core.Plugins;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Plugins;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Plugins;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Querying
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LightInject;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.DependencyInjection;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models.Identity;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml.Linq;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Linq;
|
||||
using LightInject;
|
||||
using NPoco;
|
||||
using Semver;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.DependencyInjection;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlServerCe;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LightInject;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.DependencyInjection;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LightInject;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.DependencyInjection;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Linq;
|
||||
using AutoMapper;
|
||||
using LightInject;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.DependencyInjection;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LightInject;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.DependencyInjection;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using NPoco;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core
|
||||
namespace Umbraco.Core.Plugins
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to notify the TypeFinder to ignore any class attributed with this during it's discovery
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,311 +1,310 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A utility class for type checking, this provides internal caching so that calls to these methods will be faster
|
||||
/// than doing a manual type check in c#
|
||||
/// </summary>
|
||||
internal static class TypeHelper
|
||||
{
|
||||
|
||||
private static readonly ConcurrentDictionary<Type, FieldInfo[]> GetFieldsCache = new ConcurrentDictionary<Type, FieldInfo[]>();
|
||||
private static readonly ConcurrentDictionary<Tuple<Type, bool, bool, bool>, PropertyInfo[]> GetPropertiesCache = new ConcurrentDictionary<Tuple<Type, bool, bool, bool>, PropertyInfo[]>();
|
||||
|
||||
/// <summary>
|
||||
/// Find all assembly references that are referencing the assignTypeFrom Type's assembly found in the assemblyList
|
||||
/// </summary>
|
||||
/// <param name="assignTypeFrom"></param>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// If the assembly of the assignTypeFrom Type is in the App_Code assembly, then we return nothing since things cannot
|
||||
/// reference that assembly, same with the global.asax assembly.
|
||||
/// </remarks>
|
||||
public static Assembly[] GetReferencedAssemblies(Type assignTypeFrom, IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
//check if it is the app_code assembly.
|
||||
//check if it is App_global.asax assembly
|
||||
if (assignTypeFrom.Assembly.IsAppCodeAssembly() || assignTypeFrom.Assembly.IsGlobalAsaxAssembly())
|
||||
{
|
||||
return Enumerable.Empty<Assembly>().ToArray();
|
||||
}
|
||||
|
||||
//find all assembly references that are referencing the current type's assembly since we
|
||||
//should only be scanning those assemblies because any other assembly will definitely not
|
||||
//contain sub type's of the one we're currently looking for
|
||||
return assemblies
|
||||
.Where(assembly =>
|
||||
assembly == assignTypeFrom.Assembly
|
||||
|| HasReferenceToAssemblyWithName(assembly, assignTypeFrom.Assembly.GetName().Name))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// checks if the assembly has a reference with the same name as the expected assembly name.
|
||||
/// </summary>
|
||||
/// <param name="assembly"></param>
|
||||
/// <param name="expectedAssemblyName"></param>
|
||||
/// <returns></returns>
|
||||
private static bool HasReferenceToAssemblyWithName(Assembly assembly, string expectedAssemblyName)
|
||||
{
|
||||
return assembly
|
||||
.GetReferencedAssemblies()
|
||||
.Select(a => a.Name)
|
||||
.Contains(expectedAssemblyName, StringComparer.Ordinal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the type is a class and is not static
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsNonStaticClass(Type t)
|
||||
{
|
||||
return t.IsClass && IsStaticClass(t) == false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the type is a static class
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// In IL a static class is abstract and sealed
|
||||
/// see: http://stackoverflow.com/questions/1175888/determine-if-a-type-is-static
|
||||
/// </remarks>
|
||||
public static bool IsStaticClass(Type type)
|
||||
{
|
||||
return type.IsAbstract && type.IsSealed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds a lowest base class amongst a collection of types
|
||||
/// </summary>
|
||||
/// <param name="types"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// The term 'lowest' refers to the most base class of the type collection.
|
||||
/// If a base type is not found amongst the type collection then an invalid attempt is returned.
|
||||
/// </remarks>
|
||||
public static Attempt<Type> GetLowestBaseType(params Type[] types)
|
||||
{
|
||||
if (types.Length == 0)
|
||||
{
|
||||
return Attempt<Type>.Fail();
|
||||
}
|
||||
if (types.Length == 1)
|
||||
{
|
||||
return Attempt.Succeed(types[0]);
|
||||
}
|
||||
|
||||
foreach (var curr in types)
|
||||
{
|
||||
var others = types.Except(new[] {curr});
|
||||
|
||||
//is the curr type a common denominator for all others ?
|
||||
var isBase = others.All(curr.IsAssignableFrom);
|
||||
|
||||
//if this type is the base for all others
|
||||
if (isBase)
|
||||
{
|
||||
return Attempt.Succeed(curr);
|
||||
}
|
||||
}
|
||||
|
||||
return Attempt<Type>.Fail();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the type <paramref name="implementation"/> is assignable from the specified implementation,
|
||||
/// and caches the result across the application using a <see cref="ConcurrentDictionary{TKey,TValue}"/>.
|
||||
/// </summary>
|
||||
/// <param name="contract">The type of the contract.</param>
|
||||
/// <param name="implementation">The implementation.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if [is type assignable from] [the specified contract]; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public static bool IsTypeAssignableFrom(Type contract, Type implementation)
|
||||
{
|
||||
return contract.IsAssignableFrom(implementation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the type <paramref name="implementation"/> is assignable from the specified implementation <typeparamref name="TContract"/>,
|
||||
/// and caches the result across the application using a <see cref="ConcurrentDictionary{TKey,TValue}"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="TContract">The type of the contract.</typeparam>
|
||||
/// <param name="implementation">The implementation.</param>
|
||||
public static bool IsTypeAssignableFrom<TContract>(Type implementation)
|
||||
{
|
||||
return IsTypeAssignableFrom(typeof(TContract), implementation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the object instance <paramref name="implementation"/> is assignable from the specified implementation <typeparamref name="TContract"/>,
|
||||
/// and caches the result across the application using a <see cref="ConcurrentDictionary{TKey,TValue}"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="TContract">The type of the contract.</typeparam>
|
||||
/// <param name="implementation">The implementation.</param>
|
||||
public static bool IsTypeAssignableFrom<TContract>(object implementation)
|
||||
{
|
||||
if (implementation == null) throw new ArgumentNullException("implementation");
|
||||
return IsTypeAssignableFrom<TContract>(implementation.GetType());
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns (and caches) a PropertyInfo from a type
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="mustRead"></param>
|
||||
/// <param name="mustWrite"></param>
|
||||
/// <param name="includeIndexed"></param>
|
||||
/// <param name="caseSensitive"> </param>
|
||||
/// <returns></returns>
|
||||
public static PropertyInfo GetProperty(Type type, string name,
|
||||
bool mustRead = true,
|
||||
bool mustWrite = true,
|
||||
bool includeIndexed = false,
|
||||
bool caseSensitive = true)
|
||||
{
|
||||
return CachedDiscoverableProperties(type, mustRead, mustWrite, includeIndexed)
|
||||
.FirstOrDefault(x =>
|
||||
{
|
||||
if (caseSensitive)
|
||||
return x.Name == name;
|
||||
return x.Name.InvariantEquals(name);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and caches) <see cref="PropertyInfo"/> discoverable in the current <see cref="AppDomain"/> for a given <paramref name="type"/>.
|
||||
/// </summary>
|
||||
/// <param name="type">The source.</param>
|
||||
/// <param name="mustRead">true if the properties discovered are readable</param>
|
||||
/// <param name="mustWrite">true if the properties discovered are writable</param>
|
||||
/// <param name="includeIndexed">true if the properties discovered are indexable</param>
|
||||
/// <returns></returns>
|
||||
public static PropertyInfo[] CachedDiscoverableProperties(Type type, bool mustRead = true, bool mustWrite = true, bool includeIndexed = false)
|
||||
{
|
||||
return GetPropertiesCache.GetOrAdd(
|
||||
new Tuple<Type, bool, bool, bool>(type, mustRead, mustWrite, includeIndexed),
|
||||
x => type
|
||||
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
||||
.Where(y => (!mustRead || y.CanRead)
|
||||
&& (!mustWrite || y.CanWrite)
|
||||
&& (includeIndexed || !y.GetIndexParameters().Any()))
|
||||
.ToArray());
|
||||
}
|
||||
|
||||
|
||||
#region Match Type
|
||||
|
||||
//TODO: Need to determine if these methods should replace/combine/merge etc with IsTypeAssignableFrom, IsAssignableFromGeneric
|
||||
|
||||
// readings:
|
||||
// http://stackoverflow.com/questions/2033912/c-sharp-variance-problem-assigning-listderived-as-listbase
|
||||
// http://stackoverflow.com/questions/2208043/generic-variance-in-c-sharp-4-0
|
||||
// http://stackoverflow.com/questions/8401738/c-sharp-casting-generics-covariance-and-contravariance
|
||||
// http://stackoverflow.com/questions/1827425/how-to-check-programatically-if-a-type-is-a-struct-or-a-class
|
||||
// http://stackoverflow.com/questions/74616/how-to-detect-if-type-is-another-generic-type/1075059#1075059
|
||||
|
||||
private static bool MatchGeneric(Type implementation, Type contract, IDictionary<string, Type> bindings)
|
||||
{
|
||||
// trying to match eg List<int> with List<T>
|
||||
// or List<List<List<int>>> with List<ListList<T>>>
|
||||
// classes are NOT invariant so List<string> does not match List<object>
|
||||
|
||||
if (implementation.IsGenericType == false) return false;
|
||||
|
||||
// must have the same generic type definition
|
||||
var implDef = implementation.GetGenericTypeDefinition();
|
||||
var contDef = contract.GetGenericTypeDefinition();
|
||||
if (implDef != contDef) return false;
|
||||
|
||||
// must have the same number of generic arguments
|
||||
var implArgs = implementation.GetGenericArguments();
|
||||
var contArgs = contract.GetGenericArguments();
|
||||
if (implArgs.Length != contArgs.Length) return false;
|
||||
|
||||
// generic arguments must match
|
||||
// in insta we should have actual types (eg int, string...)
|
||||
// in typea we can have generic parameters (eg <T>)
|
||||
for (var i = 0; i < implArgs.Length; i++)
|
||||
{
|
||||
const bool variance = false; // classes are NOT invariant
|
||||
if (MatchType(implArgs[i], contArgs[i], bindings, variance) == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool MatchType(Type implementation, Type contract)
|
||||
{
|
||||
return MatchType(implementation, contract, new Dictionary<string, Type>());
|
||||
}
|
||||
|
||||
internal static bool MatchType(Type implementation, Type contract, IDictionary<string, Type> bindings, bool variance = true)
|
||||
{
|
||||
if (contract.IsGenericType)
|
||||
{
|
||||
// eg type is List<int> or List<T>
|
||||
// if we have variance then List<int> can match IList<T>
|
||||
// if we don't have variance it can't - must have exact type
|
||||
|
||||
// try to match implementation against contract
|
||||
if (MatchGeneric(implementation, contract, bindings)) return true;
|
||||
|
||||
// if no variance, fail
|
||||
if (variance == false) return false;
|
||||
|
||||
// try to match an ancestor of implementation against contract
|
||||
var t = implementation.BaseType;
|
||||
while (t != null)
|
||||
{
|
||||
if (MatchGeneric(t, contract, bindings)) return true;
|
||||
t = t.BaseType;
|
||||
}
|
||||
|
||||
// try to match an interface of implementation against contract
|
||||
return implementation.GetInterfaces().Any(i => MatchGeneric(i, contract, bindings));
|
||||
}
|
||||
|
||||
if (contract.IsGenericParameter)
|
||||
{
|
||||
// eg <T>
|
||||
|
||||
if (bindings.ContainsKey(contract.Name))
|
||||
{
|
||||
// already bound: ensure it's compatible
|
||||
return bindings[contract.Name] == implementation;
|
||||
}
|
||||
|
||||
// not already bound: bind
|
||||
bindings[contract.Name] = implementation;
|
||||
return true;
|
||||
}
|
||||
|
||||
// not a generic type, not a generic parameter
|
||||
// so normal class or interface
|
||||
// fixme structs? enums? array types?
|
||||
// about primitive types, value types, etc:
|
||||
// http://stackoverflow.com/questions/1827425/how-to-check-programatically-if-a-type-is-a-struct-or-a-class
|
||||
|
||||
if (implementation == contract) return true;
|
||||
if (contract.IsClass && implementation.IsClass && implementation.IsSubclassOf(contract)) return true;
|
||||
if (contract.IsInterface && implementation.GetInterfaces().Contains(contract)) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Umbraco.Core.Plugins
|
||||
{
|
||||
/// <summary>
|
||||
/// A utility class for type checking, this provides internal caching so that calls to these methods will be faster
|
||||
/// than doing a manual type check in c#
|
||||
/// </summary>
|
||||
internal static class TypeHelper
|
||||
{
|
||||
|
||||
private static readonly ConcurrentDictionary<Type, FieldInfo[]> GetFieldsCache = new ConcurrentDictionary<Type, FieldInfo[]>();
|
||||
private static readonly ConcurrentDictionary<Tuple<Type, bool, bool, bool>, PropertyInfo[]> GetPropertiesCache = new ConcurrentDictionary<Tuple<Type, bool, bool, bool>, PropertyInfo[]>();
|
||||
|
||||
/// <summary>
|
||||
/// Find all assembly references that are referencing the assignTypeFrom Type's assembly found in the assemblyList
|
||||
/// </summary>
|
||||
/// <param name="assignTypeFrom"></param>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// If the assembly of the assignTypeFrom Type is in the App_Code assembly, then we return nothing since things cannot
|
||||
/// reference that assembly, same with the global.asax assembly.
|
||||
/// </remarks>
|
||||
public static Assembly[] GetReferencedAssemblies(Type assignTypeFrom, IEnumerable<Assembly> assemblies)
|
||||
{
|
||||
//check if it is the app_code assembly.
|
||||
//check if it is App_global.asax assembly
|
||||
if (assignTypeFrom.Assembly.IsAppCodeAssembly() || assignTypeFrom.Assembly.IsGlobalAsaxAssembly())
|
||||
{
|
||||
return Enumerable.Empty<Assembly>().ToArray();
|
||||
}
|
||||
|
||||
//find all assembly references that are referencing the current type's assembly since we
|
||||
//should only be scanning those assemblies because any other assembly will definitely not
|
||||
//contain sub type's of the one we're currently looking for
|
||||
return assemblies
|
||||
.Where(assembly =>
|
||||
assembly == assignTypeFrom.Assembly
|
||||
|| HasReferenceToAssemblyWithName(assembly, assignTypeFrom.Assembly.GetName().Name))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// checks if the assembly has a reference with the same name as the expected assembly name.
|
||||
/// </summary>
|
||||
/// <param name="assembly"></param>
|
||||
/// <param name="expectedAssemblyName"></param>
|
||||
/// <returns></returns>
|
||||
private static bool HasReferenceToAssemblyWithName(Assembly assembly, string expectedAssemblyName)
|
||||
{
|
||||
return assembly
|
||||
.GetReferencedAssemblies()
|
||||
.Select(a => a.Name)
|
||||
.Contains(expectedAssemblyName, StringComparer.Ordinal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the type is a class and is not static
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsNonStaticClass(Type t)
|
||||
{
|
||||
return t.IsClass && IsStaticClass(t) == false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the type is a static class
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// In IL a static class is abstract and sealed
|
||||
/// see: http://stackoverflow.com/questions/1175888/determine-if-a-type-is-static
|
||||
/// </remarks>
|
||||
public static bool IsStaticClass(Type type)
|
||||
{
|
||||
return type.IsAbstract && type.IsSealed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds a lowest base class amongst a collection of types
|
||||
/// </summary>
|
||||
/// <param name="types"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// The term 'lowest' refers to the most base class of the type collection.
|
||||
/// If a base type is not found amongst the type collection then an invalid attempt is returned.
|
||||
/// </remarks>
|
||||
public static Attempt<Type> GetLowestBaseType(params Type[] types)
|
||||
{
|
||||
if (types.Length == 0)
|
||||
{
|
||||
return Attempt<Type>.Fail();
|
||||
}
|
||||
if (types.Length == 1)
|
||||
{
|
||||
return Attempt.Succeed(types[0]);
|
||||
}
|
||||
|
||||
foreach (var curr in types)
|
||||
{
|
||||
var others = types.Except(new[] {curr});
|
||||
|
||||
//is the curr type a common denominator for all others ?
|
||||
var isBase = others.All(curr.IsAssignableFrom);
|
||||
|
||||
//if this type is the base for all others
|
||||
if (isBase)
|
||||
{
|
||||
return Attempt.Succeed(curr);
|
||||
}
|
||||
}
|
||||
|
||||
return Attempt<Type>.Fail();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the type <paramref name="implementation"/> is assignable from the specified implementation,
|
||||
/// and caches the result across the application using a <see cref="ConcurrentDictionary{TKey,TValue}"/>.
|
||||
/// </summary>
|
||||
/// <param name="contract">The type of the contract.</param>
|
||||
/// <param name="implementation">The implementation.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if [is type assignable from] [the specified contract]; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public static bool IsTypeAssignableFrom(Type contract, Type implementation)
|
||||
{
|
||||
return contract.IsAssignableFrom(implementation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the type <paramref name="implementation"/> is assignable from the specified implementation <typeparamref name="TContract"/>,
|
||||
/// and caches the result across the application using a <see cref="ConcurrentDictionary{TKey,TValue}"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="TContract">The type of the contract.</typeparam>
|
||||
/// <param name="implementation">The implementation.</param>
|
||||
public static bool IsTypeAssignableFrom<TContract>(Type implementation)
|
||||
{
|
||||
return IsTypeAssignableFrom(typeof(TContract), implementation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the object instance <paramref name="implementation"/> is assignable from the specified implementation <typeparamref name="TContract"/>,
|
||||
/// and caches the result across the application using a <see cref="ConcurrentDictionary{TKey,TValue}"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="TContract">The type of the contract.</typeparam>
|
||||
/// <param name="implementation">The implementation.</param>
|
||||
public static bool IsTypeAssignableFrom<TContract>(object implementation)
|
||||
{
|
||||
if (implementation == null) throw new ArgumentNullException("implementation");
|
||||
return IsTypeAssignableFrom<TContract>(implementation.GetType());
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns (and caches) a PropertyInfo from a type
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="mustRead"></param>
|
||||
/// <param name="mustWrite"></param>
|
||||
/// <param name="includeIndexed"></param>
|
||||
/// <param name="caseSensitive"> </param>
|
||||
/// <returns></returns>
|
||||
public static PropertyInfo GetProperty(Type type, string name,
|
||||
bool mustRead = true,
|
||||
bool mustWrite = true,
|
||||
bool includeIndexed = false,
|
||||
bool caseSensitive = true)
|
||||
{
|
||||
return CachedDiscoverableProperties(type, mustRead, mustWrite, includeIndexed)
|
||||
.FirstOrDefault(x =>
|
||||
{
|
||||
if (caseSensitive)
|
||||
return x.Name == name;
|
||||
return x.Name.InvariantEquals(name);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and caches) <see cref="PropertyInfo"/> discoverable in the current <see cref="AppDomain"/> for a given <paramref name="type"/>.
|
||||
/// </summary>
|
||||
/// <param name="type">The source.</param>
|
||||
/// <param name="mustRead">true if the properties discovered are readable</param>
|
||||
/// <param name="mustWrite">true if the properties discovered are writable</param>
|
||||
/// <param name="includeIndexed">true if the properties discovered are indexable</param>
|
||||
/// <returns></returns>
|
||||
public static PropertyInfo[] CachedDiscoverableProperties(Type type, bool mustRead = true, bool mustWrite = true, bool includeIndexed = false)
|
||||
{
|
||||
return GetPropertiesCache.GetOrAdd(
|
||||
new Tuple<Type, bool, bool, bool>(type, mustRead, mustWrite, includeIndexed),
|
||||
x => type
|
||||
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
||||
.Where(y => (!mustRead || y.CanRead)
|
||||
&& (!mustWrite || y.CanWrite)
|
||||
&& (includeIndexed || !y.GetIndexParameters().Any()))
|
||||
.ToArray());
|
||||
}
|
||||
|
||||
|
||||
#region Match Type
|
||||
|
||||
//TODO: Need to determine if these methods should replace/combine/merge etc with IsTypeAssignableFrom, IsAssignableFromGeneric
|
||||
|
||||
// readings:
|
||||
// http://stackoverflow.com/questions/2033912/c-sharp-variance-problem-assigning-listderived-as-listbase
|
||||
// http://stackoverflow.com/questions/2208043/generic-variance-in-c-sharp-4-0
|
||||
// http://stackoverflow.com/questions/8401738/c-sharp-casting-generics-covariance-and-contravariance
|
||||
// http://stackoverflow.com/questions/1827425/how-to-check-programatically-if-a-type-is-a-struct-or-a-class
|
||||
// http://stackoverflow.com/questions/74616/how-to-detect-if-type-is-another-generic-type/1075059#1075059
|
||||
|
||||
private static bool MatchGeneric(Type implementation, Type contract, IDictionary<string, Type> bindings)
|
||||
{
|
||||
// trying to match eg List<int> with List<T>
|
||||
// or List<List<List<int>>> with List<ListList<T>>>
|
||||
// classes are NOT invariant so List<string> does not match List<object>
|
||||
|
||||
if (implementation.IsGenericType == false) return false;
|
||||
|
||||
// must have the same generic type definition
|
||||
var implDef = implementation.GetGenericTypeDefinition();
|
||||
var contDef = contract.GetGenericTypeDefinition();
|
||||
if (implDef != contDef) return false;
|
||||
|
||||
// must have the same number of generic arguments
|
||||
var implArgs = implementation.GetGenericArguments();
|
||||
var contArgs = contract.GetGenericArguments();
|
||||
if (implArgs.Length != contArgs.Length) return false;
|
||||
|
||||
// generic arguments must match
|
||||
// in insta we should have actual types (eg int, string...)
|
||||
// in typea we can have generic parameters (eg <T>)
|
||||
for (var i = 0; i < implArgs.Length; i++)
|
||||
{
|
||||
const bool variance = false; // classes are NOT invariant
|
||||
if (MatchType(implArgs[i], contArgs[i], bindings, variance) == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool MatchType(Type implementation, Type contract)
|
||||
{
|
||||
return MatchType(implementation, contract, new Dictionary<string, Type>());
|
||||
}
|
||||
|
||||
internal static bool MatchType(Type implementation, Type contract, IDictionary<string, Type> bindings, bool variance = true)
|
||||
{
|
||||
if (contract.IsGenericType)
|
||||
{
|
||||
// eg type is List<int> or List<T>
|
||||
// if we have variance then List<int> can match IList<T>
|
||||
// if we don't have variance it can't - must have exact type
|
||||
|
||||
// try to match implementation against contract
|
||||
if (MatchGeneric(implementation, contract, bindings)) return true;
|
||||
|
||||
// if no variance, fail
|
||||
if (variance == false) return false;
|
||||
|
||||
// try to match an ancestor of implementation against contract
|
||||
var t = implementation.BaseType;
|
||||
while (t != null)
|
||||
{
|
||||
if (MatchGeneric(t, contract, bindings)) return true;
|
||||
t = t.BaseType;
|
||||
}
|
||||
|
||||
// try to match an interface of implementation against contract
|
||||
return implementation.GetInterfaces().Any(i => MatchGeneric(i, contract, bindings));
|
||||
}
|
||||
|
||||
if (contract.IsGenericParameter)
|
||||
{
|
||||
// eg <T>
|
||||
|
||||
if (bindings.ContainsKey(contract.Name))
|
||||
{
|
||||
// already bound: ensure it's compatible
|
||||
return bindings[contract.Name] == implementation;
|
||||
}
|
||||
|
||||
// not already bound: bind
|
||||
bindings[contract.Name] = implementation;
|
||||
return true;
|
||||
}
|
||||
|
||||
// not a generic type, not a generic parameter
|
||||
// so normal class or interface
|
||||
// fixme structs? enums? array types?
|
||||
// about primitive types, value types, etc:
|
||||
// http://stackoverflow.com/questions/1827425/how-to-check-programatically-if-a-type-is-a-struct-or-a-class
|
||||
|
||||
if (implementation == contract) return true;
|
||||
if (contract.IsClass && implementation.IsClass && implementation.IsSubclassOf(contract)) return true;
|
||||
if (contract.IsInterface && implementation.GetInterfaces().Contains(contract)) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ using Newtonsoft.Json;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Plugins;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Plugins;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Plugins;
|
||||
using Umbraco.Core.Strings;
|
||||
|
||||
namespace Umbraco.Core
|
||||
|
||||
@@ -148,7 +148,7 @@
|
||||
<Compile Include="AssemblyExtensions.cs" />
|
||||
<Compile Include="AsyncLock.cs" />
|
||||
<Compile Include="AttemptOfT.cs" />
|
||||
<Compile Include="CacheHelper.cs" />
|
||||
<Compile Include="Cache\CacheHelper.cs" />
|
||||
<Compile Include="Cache\CacheKeys.cs" />
|
||||
<Compile Include="Cache\CacheProviderExtensions.cs" />
|
||||
<Compile Include="Cache\DefaultRepositoryCachePolicy.cs" />
|
||||
@@ -185,7 +185,7 @@
|
||||
<Compile Include="CodeAnnotations\UmbracoExperimentalFeatureAttribute.cs" />
|
||||
<Compile Include="Collections\DeepCloneableList.cs" />
|
||||
<Compile Include="Collections\ListCloneBehavior.cs" />
|
||||
<Compile Include="ConcurrentHashSet.cs" />
|
||||
<Compile Include="Collections\ConcurrentHashSet.cs" />
|
||||
<Compile Include="Configuration\CaseInsensitiveEnumConfigConverter.cs" />
|
||||
<Compile Include="Configuration\ClientDependencyConfiguration.cs" />
|
||||
<Compile Include="Configuration\Dashboard\AccessElement.cs" />
|
||||
@@ -335,7 +335,7 @@
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Files.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="HideFromTypeFinderAttribute.cs" />
|
||||
<Compile Include="Plugins\HideFromTypeFinderAttribute.cs" />
|
||||
<Compile Include="HttpContextExtensions.cs" />
|
||||
<Compile Include="IApplicationEventHandler.cs" />
|
||||
<Compile Include="IDisposeOnRequestEnd.cs" />
|
||||
@@ -577,9 +577,8 @@
|
||||
<Compile Include="Enum.cs" />
|
||||
<Compile Include="Events\MacroErrorEventArgs.cs" />
|
||||
<Compile Include="HashCodeCombiner.cs" />
|
||||
<Compile Include="IconPickerBehaviour.cs" />
|
||||
<Compile Include="IO\FileSystemWrapper.cs" />
|
||||
<Compile Include="MacroErrorBehaviour.cs" />
|
||||
<Compile Include="Macros\MacroErrorBehaviour.cs" />
|
||||
<Compile Include="Media\IImageUrlProvider.cs" />
|
||||
<Compile Include="Models\ContentPreviewEntity.cs" />
|
||||
<Compile Include="Models\ContentTypeBase.cs" />
|
||||
@@ -759,7 +758,7 @@
|
||||
<Compile Include="Models\Validation\RequiredForPersistenceAttribute.cs" />
|
||||
<Compile Include="ObjectResolution\ApplicationEventsResolver.cs" />
|
||||
<Compile Include="ObjectResolution\ResolverCollection.cs" />
|
||||
<Compile Include="ObservableDictionary.cs" />
|
||||
<Compile Include="Collections\ObservableDictionary.cs" />
|
||||
<Compile Include="Persistence\Factories\MacroFactory.cs" />
|
||||
<Compile Include="Persistence\Factories\ModelFactoryConfiguration.cs" />
|
||||
<Compile Include="Persistence\Factories\MemberFactory.cs" />
|
||||
@@ -1070,11 +1069,11 @@
|
||||
<Compile Include="Persistence\UnitOfWork\IUnitOfWorkRepository.cs" />
|
||||
<Compile Include="Persistence\UnitOfWork\NPocoUnitOfWork.cs" />
|
||||
<Compile Include="Persistence\UnitOfWork\NPocoUnitOfWorkProvider.cs" />
|
||||
<Compile Include="Profiling\IProfiler.cs" />
|
||||
<Compile Include="Profiling\LogProfiler.cs" />
|
||||
<Compile Include="Profiling\ProfilerExtensions.cs" />
|
||||
<Compile Include="Profiling\ProfilerResolver.cs" />
|
||||
<Compile Include="Profiling\WebProfiler.cs" />
|
||||
<Compile Include="Logging\IProfiler.cs" />
|
||||
<Compile Include="Logging\LogProfiler.cs" />
|
||||
<Compile Include="Logging\ProfilerExtensions.cs" />
|
||||
<Compile Include="Logging\ProfilerResolver.cs" />
|
||||
<Compile Include="Logging\WebProfiler.cs" />
|
||||
<Compile Include="PropertyEditors\DelimitedManifestValueValidator.cs" />
|
||||
<Compile Include="PropertyEditors\IntegerValidator.cs" />
|
||||
<Compile Include="PropertyEditors\ManifestPropertyValidator.cs" />
|
||||
@@ -1180,7 +1179,7 @@
|
||||
<Compile Include="Dynamics\Signature.cs" />
|
||||
<Compile Include="ExpressionExtensions.cs" />
|
||||
<Compile Include="Models\IPublishedContent.cs" />
|
||||
<Compile Include="CacheRefreshersResolver.cs" />
|
||||
<Compile Include="Cache\CacheRefreshersResolver.cs" />
|
||||
<Compile Include="Configuration\GlobalSettings.cs" />
|
||||
<Compile Include="CustomBooleanTypeConverter.cs" />
|
||||
<Compile Include="DisposableObject.cs" />
|
||||
@@ -1320,8 +1319,8 @@
|
||||
<Compile Include="Models\ApplicationTree.cs" />
|
||||
<Compile Include="TypeExtensions.cs" />
|
||||
<Compile Include="ReadLock.cs" />
|
||||
<Compile Include="TypeFinder.cs" />
|
||||
<Compile Include="TypeHelper.cs" />
|
||||
<Compile Include="Plugins\TypeFinder.cs" />
|
||||
<Compile Include="Plugins\TypeHelper.cs" />
|
||||
<Compile Include="UmbracoApplicationBase.cs" />
|
||||
<Compile Include="Constants.cs" />
|
||||
<Compile Include="Constants-Applications.cs">
|
||||
@@ -1357,7 +1356,7 @@
|
||||
<Compile Include="Media\Status.cs" />
|
||||
<Compile Include="EnumerableExtensions.cs" />
|
||||
<Compile Include="IfExtensions.cs" />
|
||||
<Compile Include="PluginManager.cs" />
|
||||
<Compile Include="Plugins\PluginManager.cs" />
|
||||
<Compile Include="IO\FileSecurityException.cs" />
|
||||
<Compile Include="IO\FileSystemProviderManager.cs" />
|
||||
<Compile Include="IO\IFileSystem.cs" />
|
||||
@@ -1375,7 +1374,7 @@
|
||||
<Compile Include="WaitHandleExtensions.cs" />
|
||||
<Compile Include="WriteLock.cs" />
|
||||
<Compile Include="XmlExtensions.cs" />
|
||||
<Compile Include="XmlHelper.cs" />
|
||||
<Compile Include="Xml\XmlHelper.cs" />
|
||||
<Compile Include="Xml\UmbracoXPathPathSyntaxParser.cs" />
|
||||
<Compile Include="Xml\XPath\MacroNavigator.cs" />
|
||||
<Compile Include="Xml\XPath\INavigableContentType.cs" />
|
||||
@@ -1402,6 +1401,7 @@
|
||||
<LastGenOutput>Files.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
|
||||
@@ -1,470 +1,468 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml.XPath;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// The XmlHelper class contains general helper methods for working with xml in umbraco.
|
||||
/// </summary>
|
||||
public class XmlHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether a specified string contains only xml whitespace characters.
|
||||
/// </summary>
|
||||
/// <param name="s">The string.</param>
|
||||
/// <returns><c>true</c> if the string contains only xml whitespace characters.</returns>
|
||||
/// <remarks>As per XML 1.1 specs, space, \t, \r and \n.</remarks>
|
||||
public static bool IsXmlWhitespace(string s)
|
||||
{
|
||||
// as per xml 1.1 specs - anything else is significant whitespace
|
||||
s = s.Trim(' ', '\t', '\r', '\n');
|
||||
return s.Length == 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <c>XPathDocument</c> from an xml string.
|
||||
/// </summary>
|
||||
/// <param name="xml">The xml string.</param>
|
||||
/// <returns>An <c>XPathDocument</c> created from the xml string.</returns>
|
||||
public static XPathDocument CreateXPathDocument(string xml)
|
||||
{
|
||||
return new XPathDocument(new XmlTextReader(new StringReader(xml)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to create a new <c>XPathDocument</c> from an xml string.
|
||||
/// </summary>
|
||||
/// <param name="xml">The xml string.</param>
|
||||
/// <param name="doc">The XPath document.</param>
|
||||
/// <returns>A value indicating whether it has been possible to create the document.</returns>
|
||||
public static bool TryCreateXPathDocument(string xml, out XPathDocument doc)
|
||||
{
|
||||
try
|
||||
{
|
||||
doc = CreateXPathDocument(xml);
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
doc = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to create a new <c>XPathDocument</c> from a property value.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of the property.</param>
|
||||
/// <param name="doc">The XPath document.</param>
|
||||
/// <returns>A value indicating whether it has been possible to create the document.</returns>
|
||||
/// <remarks>The value can be anything... Performance-wise, this is bad.</remarks>
|
||||
public static bool TryCreateXPathDocumentFromPropertyValue(object value, out XPathDocument doc)
|
||||
{
|
||||
// DynamicNode.ConvertPropertyValueByDataType first cleans the value by calling
|
||||
// XmlHelper.StripDashesInElementOrAttributeName - this is because the XML is
|
||||
// to be returned as a DynamicXml and element names such as "value-item" are
|
||||
// invalid and must be converted to "valueitem". But we don't have that sort of
|
||||
// problem here - and we don't need to bother with dashes nor dots, etc.
|
||||
|
||||
doc = null;
|
||||
var xml = value as string;
|
||||
if (xml == null) return false; // no a string
|
||||
if (CouldItBeXml(xml) == false) return false; // string does not look like it's xml
|
||||
if (IsXmlWhitespace(xml)) return false; // string is whitespace, xml-wise
|
||||
if (TryCreateXPathDocument(xml, out doc) == false) return false; // string can't be parsed into xml
|
||||
|
||||
var nav = doc.CreateNavigator();
|
||||
if (nav.MoveToFirstChild())
|
||||
{
|
||||
//SD: This used to do this but the razor macros and the entire razor macros section is gone, it was all legacy, it seems this method isn't even
|
||||
// used apart from for tests so don't think this matters. In any case, we no longer check for this!
|
||||
|
||||
//var name = nav.LocalName; // must not match an excluded tag
|
||||
//if (UmbracoConfig.For.UmbracoSettings().Scripting.NotDynamicXmlDocumentElements.All(x => x.Element.InvariantEquals(name) == false)) return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
doc = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to create a new <c>XElement</c> from a property value.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of the property.</param>
|
||||
/// <param name="elt">The Xml element.</param>
|
||||
/// <returns>A value indicating whether it has been possible to create the element.</returns>
|
||||
/// <remarks>The value can be anything... Performance-wise, this is bad.</remarks>
|
||||
public static bool TryCreateXElementFromPropertyValue(object value, out XElement elt)
|
||||
{
|
||||
// see note above in TryCreateXPathDocumentFromPropertyValue...
|
||||
|
||||
elt = null;
|
||||
var xml = value as string;
|
||||
if (xml == null) return false; // not a string
|
||||
if (CouldItBeXml(xml) == false) return false; // string does not look like it's xml
|
||||
if (IsXmlWhitespace(xml)) return false; // string is whitespace, xml-wise
|
||||
|
||||
try
|
||||
{
|
||||
elt = XElement.Parse(xml, LoadOptions.None);
|
||||
}
|
||||
catch
|
||||
{
|
||||
elt = null;
|
||||
return false; // string can't be parsed into xml
|
||||
}
|
||||
|
||||
//SD: This used to do this but the razor macros and the entire razor macros section is gone, it was all legacy, it seems this method isn't even
|
||||
// used apart from for tests so don't think this matters. In any case, we no longer check for this!
|
||||
|
||||
//var name = elt.Name.LocalName; // must not match an excluded tag
|
||||
//if (UmbracoConfig.For.UmbracoSettings().Scripting.NotDynamicXmlDocumentElements.All(x => x.Element.InvariantEquals(name) == false))
|
||||
// return true;
|
||||
//elt = null;
|
||||
//return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sorts the children of a parentNode.
|
||||
/// </summary>
|
||||
/// <param name="parentNode">The parent node.</param>
|
||||
/// <param name="childNodesXPath">An XPath expression to select children of <paramref name="parentNode"/> to sort.</param>
|
||||
/// <param name="orderBy">A function returning the value to order the nodes by.</param>
|
||||
internal static void SortNodes(
|
||||
XmlNode parentNode,
|
||||
string childNodesXPath,
|
||||
Func<XmlNode, int> orderBy)
|
||||
{
|
||||
var sortedChildNodes = parentNode.SelectNodes(childNodesXPath).Cast<XmlNode>()
|
||||
.OrderBy(orderBy)
|
||||
.ToArray();
|
||||
|
||||
// append child nodes to last position, in sort-order
|
||||
// so all child nodes will go after the property nodes
|
||||
foreach (var node in sortedChildNodes)
|
||||
parentNode.AppendChild(node); // moves the node to the last position
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sorts the children of a parentNode if needed.
|
||||
/// </summary>
|
||||
/// <param name="parentNode">The parent node.</param>
|
||||
/// <param name="childNodesXPath">An XPath expression to select children of <paramref name="parentNode"/> to sort.</param>
|
||||
/// <param name="orderBy">A function returning the value to order the nodes by.</param>
|
||||
/// <returns>A value indicating whether sorting was needed.</returns>
|
||||
/// <remarks>same as SortNodes but will do nothing if nodes are already sorted - should improve performances.</remarks>
|
||||
internal static bool SortNodesIfNeeded(
|
||||
XmlNode parentNode,
|
||||
string childNodesXPath,
|
||||
Func<XmlNode, int> orderBy)
|
||||
{
|
||||
// ensure orderBy runs only once per node
|
||||
// checks whether nodes are already ordered
|
||||
// and actually sorts only if needed
|
||||
|
||||
var childNodesAndOrder = parentNode.SelectNodes(childNodesXPath).Cast<XmlNode>()
|
||||
.Select(x => Tuple.Create(x, orderBy(x))).ToArray();
|
||||
|
||||
var a = 0;
|
||||
foreach (var x in childNodesAndOrder)
|
||||
{
|
||||
if (a > x.Item2)
|
||||
{
|
||||
a = -1;
|
||||
break;
|
||||
}
|
||||
a = x.Item2;
|
||||
}
|
||||
|
||||
if (a >= 0)
|
||||
return false;
|
||||
|
||||
// append child nodes to last position, in sort-order
|
||||
// so all child nodes will go after the property nodes
|
||||
foreach (var x in childNodesAndOrder.OrderBy(x => x.Item2))
|
||||
parentNode.AppendChild(x.Item1); // moves the node to the last position
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sorts a single child node of a parentNode.
|
||||
/// </summary>
|
||||
/// <param name="parentNode">The parent node.</param>
|
||||
/// <param name="childNodesXPath">An XPath expression to select children of <paramref name="parentNode"/> to sort.</param>
|
||||
/// <param name="node">The child node to sort.</param>
|
||||
/// <param name="orderBy">A function returning the value to order the nodes by.</param>
|
||||
/// <returns>A value indicating whether sorting was needed.</returns>
|
||||
/// <remarks>Assuming all nodes but <paramref name="node"/> are sorted, this will move the node to
|
||||
/// the right position without moving all the nodes (as SortNodes would do) - should improve perfs.</remarks>
|
||||
internal static bool SortNode(
|
||||
XmlNode parentNode,
|
||||
string childNodesXPath,
|
||||
XmlNode node,
|
||||
Func<XmlNode, int> orderBy)
|
||||
{
|
||||
var nodeSortOrder = orderBy(node);
|
||||
var childNodesAndOrder = parentNode.SelectNodes(childNodesXPath).Cast<XmlNode>()
|
||||
.Select(x => Tuple.Create(x, orderBy(x))).ToArray();
|
||||
|
||||
// find the first node with a sortOrder > node.sortOrder
|
||||
var i = 0;
|
||||
while (i < childNodesAndOrder.Length && childNodesAndOrder[i].Item2 <= nodeSortOrder)
|
||||
i++;
|
||||
|
||||
// if one was found
|
||||
if (i < childNodesAndOrder.Length)
|
||||
{
|
||||
// and node is just before, we're done already
|
||||
// else we need to move it right before the node that was found
|
||||
if (i > 0 && childNodesAndOrder[i - 1].Item1 != node)
|
||||
{
|
||||
parentNode.InsertBefore(node, childNodesAndOrder[i].Item1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// and node is the last one, we're done already
|
||||
// else we need to append it as the last one
|
||||
if (i > 0 && childNodesAndOrder[i - 1].Item1 != node)
|
||||
{
|
||||
parentNode.AppendChild(node);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// used by DynamicNode only, see note in TryCreateXPathDocumentFromPropertyValue
|
||||
public static string StripDashesInElementOrAttributeNames(string xml)
|
||||
{
|
||||
using (var outputms = new MemoryStream())
|
||||
{
|
||||
using (TextWriter outputtw = new StreamWriter(outputms))
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
using (var tw = new StreamWriter(ms))
|
||||
{
|
||||
tw.Write(xml);
|
||||
tw.Flush();
|
||||
ms.Position = 0;
|
||||
using (var tr = new StreamReader(ms))
|
||||
{
|
||||
bool IsInsideElement = false, IsInsideQuotes = false;
|
||||
int ic = 0;
|
||||
while ((ic = tr.Read()) != -1)
|
||||
{
|
||||
if (ic == (int)'<' && !IsInsideQuotes)
|
||||
{
|
||||
if (tr.Peek() != (int)'!')
|
||||
{
|
||||
IsInsideElement = true;
|
||||
}
|
||||
}
|
||||
if (ic == (int)'>' && !IsInsideQuotes)
|
||||
{
|
||||
IsInsideElement = false;
|
||||
}
|
||||
if (ic == (int)'"')
|
||||
{
|
||||
IsInsideQuotes = !IsInsideQuotes;
|
||||
}
|
||||
if (!IsInsideElement || ic != (int)'-' || IsInsideQuotes)
|
||||
{
|
||||
outputtw.Write((char)ic);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
outputtw.Flush();
|
||||
outputms.Position = 0;
|
||||
using (TextReader outputtr = new StreamReader(outputms))
|
||||
{
|
||||
return outputtr.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Imports a XML node from text.
|
||||
/// </summary>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <param name="xmlDoc">The XML doc.</param>
|
||||
/// <returns></returns>
|
||||
public static XmlNode ImportXmlNodeFromText(string text, ref XmlDocument xmlDoc)
|
||||
{
|
||||
xmlDoc.LoadXml(text);
|
||||
return xmlDoc.FirstChild;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a file as a XmlDocument.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The relative file path. ei. /config/umbraco.config</param>
|
||||
/// <returns>Returns a XmlDocument class</returns>
|
||||
public static XmlDocument OpenAsXmlDocument(string filePath)
|
||||
{
|
||||
|
||||
var reader = new XmlTextReader(IOHelper.MapPath(filePath)) {WhitespaceHandling = WhitespaceHandling.All};
|
||||
|
||||
var xmlDoc = new XmlDocument();
|
||||
//Load the file into the XmlDocument
|
||||
xmlDoc.Load(reader);
|
||||
//Close off the connection to the file.
|
||||
reader.Close();
|
||||
|
||||
return xmlDoc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// creates a XmlAttribute with the specified name and value
|
||||
/// </summary>
|
||||
/// <param name="xd">The xmldocument.</param>
|
||||
/// <param name="name">The name of the attribute.</param>
|
||||
/// <param name="value">The value of the attribute.</param>
|
||||
/// <returns>a XmlAttribute</returns>
|
||||
public static XmlAttribute AddAttribute(XmlDocument xd, string name, string value)
|
||||
{
|
||||
var temp = xd.CreateAttribute(name);
|
||||
temp.Value = value;
|
||||
return temp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a text XmlNode with the specified name and value
|
||||
/// </summary>
|
||||
/// <param name="xd">The xmldocument.</param>
|
||||
/// <param name="name">The node name.</param>
|
||||
/// <param name="value">The node value.</param>
|
||||
/// <returns>a XmlNode</returns>
|
||||
public static XmlNode AddTextNode(XmlDocument xd, string name, string value)
|
||||
{
|
||||
var temp = xd.CreateNode(XmlNodeType.Element, name, "");
|
||||
temp.AppendChild(xd.CreateTextNode(value));
|
||||
return temp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a cdata XmlNode with the specified name and value
|
||||
/// </summary>
|
||||
/// <param name="xd">The xmldocument.</param>
|
||||
/// <param name="name">The node name.</param>
|
||||
/// <param name="value">The node value.</param>
|
||||
/// <returns>A XmlNode</returns>
|
||||
public static XmlNode AddCDataNode(XmlDocument xd, string name, string value)
|
||||
{
|
||||
var temp = xd.CreateNode(XmlNodeType.Element, name, "");
|
||||
temp.AppendChild(xd.CreateCDataSection(value));
|
||||
return temp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of a XmlNode
|
||||
/// </summary>
|
||||
/// <param name="n">The XmlNode.</param>
|
||||
/// <returns>the value as a string</returns>
|
||||
public static string GetNodeValue(XmlNode n)
|
||||
{
|
||||
var value = string.Empty;
|
||||
if (n == null || n.FirstChild == null)
|
||||
return value;
|
||||
value = n.FirstChild.Value ?? n.InnerXml;
|
||||
return value.Replace("<!--CDATAOPENTAG-->", "<![CDATA[").Replace("<!--CDATACLOSETAG-->", "]]>");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified string appears to be XML.
|
||||
/// </summary>
|
||||
/// <param name="xml">The XML string.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified string appears to be XML; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public static bool CouldItBeXml(string xml)
|
||||
{
|
||||
if (string.IsNullOrEmpty(xml)) return false;
|
||||
|
||||
xml = xml.Trim();
|
||||
return xml.StartsWith("<") && xml.EndsWith(">") && xml.Contains('/');
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits the specified delimited string into an XML document.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
/// <param name="separator">The separator.</param>
|
||||
/// <param name="rootName">Name of the root.</param>
|
||||
/// <param name="elementName">Name of the element.</param>
|
||||
/// <returns>Returns an <c>System.Xml.XmlDocument</c> representation of the delimited string data.</returns>
|
||||
public static XmlDocument Split(string data, string[] separator, string rootName, string elementName)
|
||||
{
|
||||
return Split(new XmlDocument(), data, separator, rootName, elementName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits the specified delimited string into an XML document.
|
||||
/// </summary>
|
||||
/// <param name="xml">The XML document.</param>
|
||||
/// <param name="data">The delimited string data.</param>
|
||||
/// <param name="separator">The separator.</param>
|
||||
/// <param name="rootName">Name of the root node.</param>
|
||||
/// <param name="elementName">Name of the element node.</param>
|
||||
/// <returns>Returns an <c>System.Xml.XmlDocument</c> representation of the delimited string data.</returns>
|
||||
public static XmlDocument Split(XmlDocument xml, string data, string[] separator, string rootName, string elementName)
|
||||
{
|
||||
// load new XML document.
|
||||
xml.LoadXml(string.Concat("<", rootName, "/>"));
|
||||
|
||||
// get the data-value, check it isn't empty.
|
||||
if (!string.IsNullOrEmpty(data))
|
||||
{
|
||||
// explode the values into an array
|
||||
var values = data.Split(separator, StringSplitOptions.None);
|
||||
|
||||
// loop through the array items.
|
||||
foreach (string value in values)
|
||||
{
|
||||
// add each value to the XML document.
|
||||
var xn = XmlHelper.AddTextNode(xml, elementName, value);
|
||||
xml.DocumentElement.AppendChild(xn);
|
||||
}
|
||||
}
|
||||
|
||||
// return the XML node.
|
||||
return xml;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a dictionary of attributes found for a string based tag
|
||||
/// </summary>
|
||||
/// <param name="tag"></param>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<string, string> GetAttributesFromElement(string tag)
|
||||
{
|
||||
var m =
|
||||
Regex.Matches(tag, "(?<attributeName>\\S*)=\"(?<attributeValue>[^\"]*)\"",
|
||||
RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
|
||||
// fix for issue 14862: return lowercase attributes for case insensitive matching
|
||||
var d = m.Cast<Match>().ToDictionary(attributeSet => attributeSet.Groups["attributeName"].Value.ToString().ToLower(), attributeSet => attributeSet.Groups["attributeValue"].Value.ToString());
|
||||
return d;
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml.XPath;
|
||||
using Umbraco.Core.IO;
|
||||
|
||||
namespace Umbraco.Core.Xml
|
||||
{
|
||||
/// <summary>
|
||||
/// The XmlHelper class contains general helper methods for working with xml in umbraco.
|
||||
/// </summary>
|
||||
public class XmlHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether a specified string contains only xml whitespace characters.
|
||||
/// </summary>
|
||||
/// <param name="s">The string.</param>
|
||||
/// <returns><c>true</c> if the string contains only xml whitespace characters.</returns>
|
||||
/// <remarks>As per XML 1.1 specs, space, \t, \r and \n.</remarks>
|
||||
public static bool IsXmlWhitespace(string s)
|
||||
{
|
||||
// as per xml 1.1 specs - anything else is significant whitespace
|
||||
s = s.Trim(' ', '\t', '\r', '\n');
|
||||
return s.Length == 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <c>XPathDocument</c> from an xml string.
|
||||
/// </summary>
|
||||
/// <param name="xml">The xml string.</param>
|
||||
/// <returns>An <c>XPathDocument</c> created from the xml string.</returns>
|
||||
public static XPathDocument CreateXPathDocument(string xml)
|
||||
{
|
||||
return new XPathDocument(new XmlTextReader(new StringReader(xml)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to create a new <c>XPathDocument</c> from an xml string.
|
||||
/// </summary>
|
||||
/// <param name="xml">The xml string.</param>
|
||||
/// <param name="doc">The XPath document.</param>
|
||||
/// <returns>A value indicating whether it has been possible to create the document.</returns>
|
||||
public static bool TryCreateXPathDocument(string xml, out XPathDocument doc)
|
||||
{
|
||||
try
|
||||
{
|
||||
doc = CreateXPathDocument(xml);
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
doc = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to create a new <c>XPathDocument</c> from a property value.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of the property.</param>
|
||||
/// <param name="doc">The XPath document.</param>
|
||||
/// <returns>A value indicating whether it has been possible to create the document.</returns>
|
||||
/// <remarks>The value can be anything... Performance-wise, this is bad.</remarks>
|
||||
public static bool TryCreateXPathDocumentFromPropertyValue(object value, out XPathDocument doc)
|
||||
{
|
||||
// DynamicNode.ConvertPropertyValueByDataType first cleans the value by calling
|
||||
// XmlHelper.StripDashesInElementOrAttributeName - this is because the XML is
|
||||
// to be returned as a DynamicXml and element names such as "value-item" are
|
||||
// invalid and must be converted to "valueitem". But we don't have that sort of
|
||||
// problem here - and we don't need to bother with dashes nor dots, etc.
|
||||
|
||||
doc = null;
|
||||
var xml = value as string;
|
||||
if (xml == null) return false; // no a string
|
||||
if (CouldItBeXml(xml) == false) return false; // string does not look like it's xml
|
||||
if (IsXmlWhitespace(xml)) return false; // string is whitespace, xml-wise
|
||||
if (TryCreateXPathDocument(xml, out doc) == false) return false; // string can't be parsed into xml
|
||||
|
||||
var nav = doc.CreateNavigator();
|
||||
if (nav.MoveToFirstChild())
|
||||
{
|
||||
//SD: This used to do this but the razor macros and the entire razor macros section is gone, it was all legacy, it seems this method isn't even
|
||||
// used apart from for tests so don't think this matters. In any case, we no longer check for this!
|
||||
|
||||
//var name = nav.LocalName; // must not match an excluded tag
|
||||
//if (UmbracoConfig.For.UmbracoSettings().Scripting.NotDynamicXmlDocumentElements.All(x => x.Element.InvariantEquals(name) == false)) return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
doc = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to create a new <c>XElement</c> from a property value.
|
||||
/// </summary>
|
||||
/// <param name="value">The value of the property.</param>
|
||||
/// <param name="elt">The Xml element.</param>
|
||||
/// <returns>A value indicating whether it has been possible to create the element.</returns>
|
||||
/// <remarks>The value can be anything... Performance-wise, this is bad.</remarks>
|
||||
public static bool TryCreateXElementFromPropertyValue(object value, out XElement elt)
|
||||
{
|
||||
// see note above in TryCreateXPathDocumentFromPropertyValue...
|
||||
|
||||
elt = null;
|
||||
var xml = value as string;
|
||||
if (xml == null) return false; // not a string
|
||||
if (CouldItBeXml(xml) == false) return false; // string does not look like it's xml
|
||||
if (IsXmlWhitespace(xml)) return false; // string is whitespace, xml-wise
|
||||
|
||||
try
|
||||
{
|
||||
elt = XElement.Parse(xml, LoadOptions.None);
|
||||
}
|
||||
catch
|
||||
{
|
||||
elt = null;
|
||||
return false; // string can't be parsed into xml
|
||||
}
|
||||
|
||||
//SD: This used to do this but the razor macros and the entire razor macros section is gone, it was all legacy, it seems this method isn't even
|
||||
// used apart from for tests so don't think this matters. In any case, we no longer check for this!
|
||||
|
||||
//var name = elt.Name.LocalName; // must not match an excluded tag
|
||||
//if (UmbracoConfig.For.UmbracoSettings().Scripting.NotDynamicXmlDocumentElements.All(x => x.Element.InvariantEquals(name) == false))
|
||||
// return true;
|
||||
//elt = null;
|
||||
//return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sorts the children of a parentNode.
|
||||
/// </summary>
|
||||
/// <param name="parentNode">The parent node.</param>
|
||||
/// <param name="childNodesXPath">An XPath expression to select children of <paramref name="parentNode"/> to sort.</param>
|
||||
/// <param name="orderBy">A function returning the value to order the nodes by.</param>
|
||||
internal static void SortNodes(
|
||||
XmlNode parentNode,
|
||||
string childNodesXPath,
|
||||
Func<XmlNode, int> orderBy)
|
||||
{
|
||||
var sortedChildNodes = parentNode.SelectNodes(childNodesXPath).Cast<XmlNode>()
|
||||
.OrderBy(orderBy)
|
||||
.ToArray();
|
||||
|
||||
// append child nodes to last position, in sort-order
|
||||
// so all child nodes will go after the property nodes
|
||||
foreach (var node in sortedChildNodes)
|
||||
parentNode.AppendChild(node); // moves the node to the last position
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sorts the children of a parentNode if needed.
|
||||
/// </summary>
|
||||
/// <param name="parentNode">The parent node.</param>
|
||||
/// <param name="childNodesXPath">An XPath expression to select children of <paramref name="parentNode"/> to sort.</param>
|
||||
/// <param name="orderBy">A function returning the value to order the nodes by.</param>
|
||||
/// <returns>A value indicating whether sorting was needed.</returns>
|
||||
/// <remarks>same as SortNodes but will do nothing if nodes are already sorted - should improve performances.</remarks>
|
||||
internal static bool SortNodesIfNeeded(
|
||||
XmlNode parentNode,
|
||||
string childNodesXPath,
|
||||
Func<XmlNode, int> orderBy)
|
||||
{
|
||||
// ensure orderBy runs only once per node
|
||||
// checks whether nodes are already ordered
|
||||
// and actually sorts only if needed
|
||||
|
||||
var childNodesAndOrder = parentNode.SelectNodes(childNodesXPath).Cast<XmlNode>()
|
||||
.Select(x => Tuple.Create(x, orderBy(x))).ToArray();
|
||||
|
||||
var a = 0;
|
||||
foreach (var x in childNodesAndOrder)
|
||||
{
|
||||
if (a > x.Item2)
|
||||
{
|
||||
a = -1;
|
||||
break;
|
||||
}
|
||||
a = x.Item2;
|
||||
}
|
||||
|
||||
if (a >= 0)
|
||||
return false;
|
||||
|
||||
// append child nodes to last position, in sort-order
|
||||
// so all child nodes will go after the property nodes
|
||||
foreach (var x in childNodesAndOrder.OrderBy(x => x.Item2))
|
||||
parentNode.AppendChild(x.Item1); // moves the node to the last position
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sorts a single child node of a parentNode.
|
||||
/// </summary>
|
||||
/// <param name="parentNode">The parent node.</param>
|
||||
/// <param name="childNodesXPath">An XPath expression to select children of <paramref name="parentNode"/> to sort.</param>
|
||||
/// <param name="node">The child node to sort.</param>
|
||||
/// <param name="orderBy">A function returning the value to order the nodes by.</param>
|
||||
/// <returns>A value indicating whether sorting was needed.</returns>
|
||||
/// <remarks>Assuming all nodes but <paramref name="node"/> are sorted, this will move the node to
|
||||
/// the right position without moving all the nodes (as SortNodes would do) - should improve perfs.</remarks>
|
||||
internal static bool SortNode(
|
||||
XmlNode parentNode,
|
||||
string childNodesXPath,
|
||||
XmlNode node,
|
||||
Func<XmlNode, int> orderBy)
|
||||
{
|
||||
var nodeSortOrder = orderBy(node);
|
||||
var childNodesAndOrder = parentNode.SelectNodes(childNodesXPath).Cast<XmlNode>()
|
||||
.Select(x => Tuple.Create(x, orderBy(x))).ToArray();
|
||||
|
||||
// find the first node with a sortOrder > node.sortOrder
|
||||
var i = 0;
|
||||
while (i < childNodesAndOrder.Length && childNodesAndOrder[i].Item2 <= nodeSortOrder)
|
||||
i++;
|
||||
|
||||
// if one was found
|
||||
if (i < childNodesAndOrder.Length)
|
||||
{
|
||||
// and node is just before, we're done already
|
||||
// else we need to move it right before the node that was found
|
||||
if (i > 0 && childNodesAndOrder[i - 1].Item1 != node)
|
||||
{
|
||||
parentNode.InsertBefore(node, childNodesAndOrder[i].Item1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// and node is the last one, we're done already
|
||||
// else we need to append it as the last one
|
||||
if (i > 0 && childNodesAndOrder[i - 1].Item1 != node)
|
||||
{
|
||||
parentNode.AppendChild(node);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// used by DynamicNode only, see note in TryCreateXPathDocumentFromPropertyValue
|
||||
public static string StripDashesInElementOrAttributeNames(string xml)
|
||||
{
|
||||
using (var outputms = new MemoryStream())
|
||||
{
|
||||
using (TextWriter outputtw = new StreamWriter(outputms))
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
using (var tw = new StreamWriter(ms))
|
||||
{
|
||||
tw.Write(xml);
|
||||
tw.Flush();
|
||||
ms.Position = 0;
|
||||
using (var tr = new StreamReader(ms))
|
||||
{
|
||||
bool IsInsideElement = false, IsInsideQuotes = false;
|
||||
int ic = 0;
|
||||
while ((ic = tr.Read()) != -1)
|
||||
{
|
||||
if (ic == (int)'<' && !IsInsideQuotes)
|
||||
{
|
||||
if (tr.Peek() != (int)'!')
|
||||
{
|
||||
IsInsideElement = true;
|
||||
}
|
||||
}
|
||||
if (ic == (int)'>' && !IsInsideQuotes)
|
||||
{
|
||||
IsInsideElement = false;
|
||||
}
|
||||
if (ic == (int)'"')
|
||||
{
|
||||
IsInsideQuotes = !IsInsideQuotes;
|
||||
}
|
||||
if (!IsInsideElement || ic != (int)'-' || IsInsideQuotes)
|
||||
{
|
||||
outputtw.Write((char)ic);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
outputtw.Flush();
|
||||
outputms.Position = 0;
|
||||
using (TextReader outputtr = new StreamReader(outputms))
|
||||
{
|
||||
return outputtr.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Imports a XML node from text.
|
||||
/// </summary>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <param name="xmlDoc">The XML doc.</param>
|
||||
/// <returns></returns>
|
||||
public static XmlNode ImportXmlNodeFromText(string text, ref XmlDocument xmlDoc)
|
||||
{
|
||||
xmlDoc.LoadXml(text);
|
||||
return xmlDoc.FirstChild;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a file as a XmlDocument.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The relative file path. ei. /config/umbraco.config</param>
|
||||
/// <returns>Returns a XmlDocument class</returns>
|
||||
public static XmlDocument OpenAsXmlDocument(string filePath)
|
||||
{
|
||||
|
||||
var reader = new XmlTextReader(IOHelper.MapPath(filePath)) {WhitespaceHandling = WhitespaceHandling.All};
|
||||
|
||||
var xmlDoc = new XmlDocument();
|
||||
//Load the file into the XmlDocument
|
||||
xmlDoc.Load(reader);
|
||||
//Close off the connection to the file.
|
||||
reader.Close();
|
||||
|
||||
return xmlDoc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// creates a XmlAttribute with the specified name and value
|
||||
/// </summary>
|
||||
/// <param name="xd">The xmldocument.</param>
|
||||
/// <param name="name">The name of the attribute.</param>
|
||||
/// <param name="value">The value of the attribute.</param>
|
||||
/// <returns>a XmlAttribute</returns>
|
||||
public static XmlAttribute AddAttribute(XmlDocument xd, string name, string value)
|
||||
{
|
||||
var temp = xd.CreateAttribute(name);
|
||||
temp.Value = value;
|
||||
return temp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a text XmlNode with the specified name and value
|
||||
/// </summary>
|
||||
/// <param name="xd">The xmldocument.</param>
|
||||
/// <param name="name">The node name.</param>
|
||||
/// <param name="value">The node value.</param>
|
||||
/// <returns>a XmlNode</returns>
|
||||
public static XmlNode AddTextNode(XmlDocument xd, string name, string value)
|
||||
{
|
||||
var temp = xd.CreateNode(XmlNodeType.Element, name, "");
|
||||
temp.AppendChild(xd.CreateTextNode(value));
|
||||
return temp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a cdata XmlNode with the specified name and value
|
||||
/// </summary>
|
||||
/// <param name="xd">The xmldocument.</param>
|
||||
/// <param name="name">The node name.</param>
|
||||
/// <param name="value">The node value.</param>
|
||||
/// <returns>A XmlNode</returns>
|
||||
public static XmlNode AddCDataNode(XmlDocument xd, string name, string value)
|
||||
{
|
||||
var temp = xd.CreateNode(XmlNodeType.Element, name, "");
|
||||
temp.AppendChild(xd.CreateCDataSection(value));
|
||||
return temp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value of a XmlNode
|
||||
/// </summary>
|
||||
/// <param name="n">The XmlNode.</param>
|
||||
/// <returns>the value as a string</returns>
|
||||
public static string GetNodeValue(XmlNode n)
|
||||
{
|
||||
var value = string.Empty;
|
||||
if (n == null || n.FirstChild == null)
|
||||
return value;
|
||||
value = n.FirstChild.Value ?? n.InnerXml;
|
||||
return value.Replace("<!--CDATAOPENTAG-->", "<![CDATA[").Replace("<!--CDATACLOSETAG-->", "]]>");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified string appears to be XML.
|
||||
/// </summary>
|
||||
/// <param name="xml">The XML string.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified string appears to be XML; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public static bool CouldItBeXml(string xml)
|
||||
{
|
||||
if (string.IsNullOrEmpty(xml)) return false;
|
||||
|
||||
xml = xml.Trim();
|
||||
return xml.StartsWith("<") && xml.EndsWith(">") && xml.Contains('/');
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits the specified delimited string into an XML document.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
/// <param name="separator">The separator.</param>
|
||||
/// <param name="rootName">Name of the root.</param>
|
||||
/// <param name="elementName">Name of the element.</param>
|
||||
/// <returns>Returns an <c>System.Xml.XmlDocument</c> representation of the delimited string data.</returns>
|
||||
public static XmlDocument Split(string data, string[] separator, string rootName, string elementName)
|
||||
{
|
||||
return Split(new XmlDocument(), data, separator, rootName, elementName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits the specified delimited string into an XML document.
|
||||
/// </summary>
|
||||
/// <param name="xml">The XML document.</param>
|
||||
/// <param name="data">The delimited string data.</param>
|
||||
/// <param name="separator">The separator.</param>
|
||||
/// <param name="rootName">Name of the root node.</param>
|
||||
/// <param name="elementName">Name of the element node.</param>
|
||||
/// <returns>Returns an <c>System.Xml.XmlDocument</c> representation of the delimited string data.</returns>
|
||||
public static XmlDocument Split(XmlDocument xml, string data, string[] separator, string rootName, string elementName)
|
||||
{
|
||||
// load new XML document.
|
||||
xml.LoadXml(string.Concat("<", rootName, "/>"));
|
||||
|
||||
// get the data-value, check it isn't empty.
|
||||
if (!string.IsNullOrEmpty(data))
|
||||
{
|
||||
// explode the values into an array
|
||||
var values = data.Split(separator, StringSplitOptions.None);
|
||||
|
||||
// loop through the array items.
|
||||
foreach (string value in values)
|
||||
{
|
||||
// add each value to the XML document.
|
||||
var xn = XmlHelper.AddTextNode(xml, elementName, value);
|
||||
xml.DocumentElement.AppendChild(xn);
|
||||
}
|
||||
}
|
||||
|
||||
// return the XML node.
|
||||
return xml;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a dictionary of attributes found for a string based tag
|
||||
/// </summary>
|
||||
/// <param name="tag"></param>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<string, string> GetAttributesFromElement(string tag)
|
||||
{
|
||||
var m =
|
||||
Regex.Matches(tag, "(?<attributeName>\\S*)=\"(?<attributeValue>[^\"]*)\"",
|
||||
RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
|
||||
// fix for issue 14862: return lowercase attributes for case insensitive matching
|
||||
var d = m.Cast<Match>().ToDictionary(attributeSet => attributeSet.Groups["attributeName"].Value.ToString().ToLower(), attributeSet => attributeSet.Groups["attributeValue"].Value.ToString());
|
||||
return d;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using Moq;
|
||||
using NUnit.Framework;
|
||||
using Semver;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
|
||||
@@ -5,6 +5,7 @@ using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Macros;
|
||||
|
||||
namespace Umbraco.Tests.Configurations.UmbracoSettings
|
||||
{
|
||||
|
||||
@@ -10,6 +10,7 @@ using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Migrations;
|
||||
using Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Plugins;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using GlobalSettings = Umbraco.Core.Configuration.GlobalSettings;
|
||||
|
||||
@@ -16,6 +16,7 @@ using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Core.Profiling;
|
||||
using Umbraco.Core.Services;
|
||||
using Moq;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web.Routing;
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using AutoMapper;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Manifest;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
@@ -27,8 +28,8 @@ namespace Umbraco.Tests.Models.Mapping
|
||||
Logger,
|
||||
typeListProducerList,
|
||||
new ManifestBuilder(
|
||||
Core.CacheHelper.CreateDisabledCacheHelper().RuntimeCache,
|
||||
new ManifestParser(Logger, new DirectoryInfo(TestHelper.CurrentAssemblyDirectory), Core.CacheHelper.CreateDisabledCacheHelper().RuntimeCache)));
|
||||
CacheHelper.CreateDisabledCacheHelper().RuntimeCache,
|
||||
new ManifestParser(Logger, new DirectoryInfo(TestHelper.CurrentAssemblyDirectory), CacheHelper.CreateDisabledCacheHelper().RuntimeCache)));
|
||||
|
||||
PropertyEditorResolver.Current = propertyEditorResolver;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using Moq;
|
||||
using NPoco;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
@@ -10,6 +10,7 @@ using NPoco;
|
||||
using NUnit.Framework;
|
||||
using Semver;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence;
|
||||
|
||||
@@ -5,6 +5,7 @@ using AutoMapper;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Plugins;
|
||||
|
||||
namespace Umbraco.Tests.Plugins
|
||||
{
|
||||
|
||||
@@ -18,6 +18,7 @@ using Umbraco.Core.Profiling;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using umbraco.DataLayer;
|
||||
using umbraco.uicontrols;
|
||||
using Umbraco.Core.Plugins;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web.PropertyEditors;
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ using Umbraco.Core;
|
||||
using Umbraco.Core.IO;
|
||||
using umbraco.DataLayer;
|
||||
using umbraco.uicontrols;
|
||||
using Umbraco.Core.Plugins;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web.Models.Trees;
|
||||
using Umbraco.Web.Trees;
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Reflection;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Plugins;
|
||||
using Umbraco.Tests.DynamicsAndReflection;
|
||||
using Umbraco.Web.Cache;
|
||||
using Umbraco.Web.Models;
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Globalization;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Profiling;
|
||||
|
||||
@@ -9,6 +9,7 @@ using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Dynamics;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.Plugins;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Xml.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Dynamics;
|
||||
using Umbraco.Core.Xml;
|
||||
|
||||
namespace Umbraco.Tests.PublishedContent
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Dynamics;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Xml;
|
||||
|
||||
namespace Umbraco.Tests.PublishedContent
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@ using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using umbraco.BusinessLogic;
|
||||
using Umbraco.Core.Plugins;
|
||||
using Umbraco.Web.PublishedCache.XmlPublishedCache;
|
||||
using Umbraco.Web.Security;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.Plugins;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Web;
|
||||
|
||||
@@ -5,6 +5,7 @@ using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Plugins;
|
||||
using Umbraco.Core.Profiling;
|
||||
using Umbraco.Core._Legacy.PackageActions;
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.Routing;
|
||||
using Umbraco.Web.WebApi;
|
||||
using umbraco.BusinessLogic;
|
||||
using Umbraco.Core.Plugins;
|
||||
using Umbraco.Core.Profiling;
|
||||
using Umbraco.Core.Strings;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using Microsoft.Owin;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ using System.Threading;
|
||||
using NPoco;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
|
||||
@@ -8,6 +8,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using NPoco;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
@@ -26,6 +26,7 @@ using Umbraco.Web.PublishedCache;
|
||||
using Umbraco.Web.PublishedCache.XmlPublishedCache;
|
||||
using Umbraco.Web.Security;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Plugins;
|
||||
using File = System.IO.File;
|
||||
|
||||
namespace Umbraco.Tests.TestHelpers
|
||||
|
||||
@@ -23,6 +23,7 @@ using Umbraco.Web;
|
||||
using Umbraco.Core.DependencyInjection;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Plugins;
|
||||
using Umbraco.Web.DependencyInjection;
|
||||
|
||||
namespace Umbraco.Tests.TestHelpers
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user