diff --git a/src/Libraries/SmartStore.Core/Async/AsyncRunner.cs b/src/Libraries/SmartStore.Core/Async/AsyncRunner.cs
index 91ffb0db95..3d61b087ca 100644
--- a/src/Libraries/SmartStore.Core/Async/AsyncRunner.cs
+++ b/src/Libraries/SmartStore.Core/Async/AsyncRunner.cs
@@ -1,8 +1,9 @@
+#if FALSE // TODO: Migrate to ASP.NET Core
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
-using System.Web.Hosting;
+using Microsoft.AspNetCore.Hosting;
using Autofac;
using SmartStore.Core.Infrastructure;
@@ -421,4 +422,6 @@ private void FinalShutdown()
}
}
-}
\ No newline at end of file
+}#endif
+
+#endif
diff --git a/src/Libraries/SmartStore.Core/Async/LocalAsyncState.cs b/src/Libraries/SmartStore.Core/Async/LocalAsyncState.cs
index ba66c15bf0..944c2387a8 100644
--- a/src/Libraries/SmartStore.Core/Async/LocalAsyncState.cs
+++ b/src/Libraries/SmartStore.Core/Async/LocalAsyncState.cs
@@ -1,7 +1,8 @@
+#if FALSE // TODO: Migrate to ASP.NET Core
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Runtime.Caching;
+// using System.Runtime.Caching; // TODO: Replace with Microsoft.Extensions.Caching.Memory
using System.Threading;
namespace SmartStore.Core.Async
@@ -197,3 +198,4 @@ protected virtual string BuildKey(Type type, string name)
}
}
}
+#endif
diff --git a/src/Libraries/SmartStore.Core/BaseEntity.cs b/src/Libraries/SmartStore.Core/BaseEntity.cs
index e2882f9851..b29eca3356 100644
--- a/src/Libraries/SmartStore.Core/BaseEntity.cs
+++ b/src/Libraries/SmartStore.Core/BaseEntity.cs
@@ -1,6 +1,5 @@
using System;
using System.ComponentModel.DataAnnotations.Schema;
-using System.Data.Entity.Core.Objects;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
@@ -30,18 +29,13 @@ public virtual string GetEntityName()
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Type GetUnproxiedType()
{
- #region Old
- //var t = GetType();
- //if (t.AssemblyQualifiedName.StartsWith("System.Data.Entity."))
- //{
- // // it's a proxied type
- // t = t.BaseType;
- //}
-
- //return t;
- #endregion
-
- return ObjectContext.GetObjectType(GetType());
+ var t = GetType();
+ // EF Core proxies have different naming pattern
+ if (t.Namespace != null && t.Namespace.StartsWith("Castle.Proxies"))
+ {
+ t = t.BaseType;
+ }
+ return t;
}
///
diff --git a/src/Libraries/SmartStore.Core/Caching/MemoryCacheManager.cs b/src/Libraries/SmartStore.Core/Caching/MemoryCacheManager.cs
index 332b199c61..cc09197755 100644
--- a/src/Libraries/SmartStore.Core/Caching/MemoryCacheManager.cs
+++ b/src/Libraries/SmartStore.Core/Caching/MemoryCacheManager.cs
@@ -1,254 +1,104 @@
using System;
-using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
-using System.Runtime.Caching;
-using System.Runtime.CompilerServices;
-using System.Text.RegularExpressions;
-using System.Threading;
using System.Threading.Tasks;
+using Microsoft.Extensions.Caching.Memory;
using SmartStore.Core.Infrastructure.DependencyManagement;
-using SmartStore.Utilities;
-using SmartStore.Utilities.Threading;
namespace SmartStore.Core.Caching
{
- public partial class MemoryCacheManager : DisposableObject, ICacheManager
+ public partial class MemoryCacheManager : ICacheManager
{
- const string LockRecursionExceptionMessage = "Acquiring identical cache items recursively is not supported. Key: {0}";
-
- // We put a special string into cache if value is null,
- // otherwise our 'Contains()' would always return false,
- // which is bad if we intentionally wanted to save NULL values.
public const string FakeNull = "__[NULL]__";
+ private readonly IMemoryCache _cache;
private readonly Work _scopeAccessor;
- private MemoryCache _cache;
- public MemoryCacheManager(Work scopeAccessor)
+ public MemoryCacheManager(IMemoryCache cache, Work scopeAccessor)
{
+ _cache = cache;
_scopeAccessor = scopeAccessor;
- _cache = CreateCache();
- }
-
- private MemoryCache CreateCache()
- {
- return new MemoryCache("SmartStore");
}
public bool IsDistributedCache => false;
- private bool TryGet(string key, bool independent, out T value)
- {
- value = default(T);
-
- object obj = _cache.Get(key);
-
- if (obj != null)
- {
- // Make the parent scope's entry depend on this
- if (!independent)
- {
- _scopeAccessor.Value.PropagateKey(key);
- }
-
- if (obj.Equals(FakeNull))
- {
- return true;
- }
-
- value = (T)obj;
- return true;
- }
-
- return false;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
public T Get(string key, bool independent = false)
{
- TryGet(key, independent, out T value);
- return value;
+ return _cache.TryGetValue(key, out T value) ? value : default(T);
}
public T Get(string key, Func acquirer, TimeSpan? duration = null, bool independent = false, bool allowRecursion = false)
{
- if (TryGet(key, independent, out T value))
+ if (_cache.TryGetValue(key, out T value))
{
return value;
}
- if (!allowRecursion && _scopeAccessor.Value.HasScope(key))
- {
- throw new LockRecursionException(LockRecursionExceptionMessage.FormatInvariant(key));
- }
-
- // Get the (semaphore) locker specific to this key
- using (KeyedLock.Lock("cache:" + key, TimeSpan.FromSeconds(5)))
- {
- // Atomic operation must be outer locked
- if (!TryGet(key, independent, out value))
- {
- var scope = !allowRecursion ? _scopeAccessor.Value.BeginScope(key) : ActionDisposable.Empty;
- using (scope)
- {
- value = acquirer();
- var dependencies = !allowRecursion ? _scopeAccessor.Value.Current?.Dependencies : (IEnumerable)null;
- Put(key, value, duration, dependencies);
- return value;
- }
- }
- }
-
+ value = acquirer();
+ Set(key, value, duration.HasValue ? (int)duration.Value.TotalMinutes : (int?)null);
return value;
}
public async Task GetAsync(string key, Func> acquirer, TimeSpan? duration = null, bool independent = false, bool allowRecursion = false)
{
- if (TryGet(key, independent, out T value))
+ if (_cache.TryGetValue(key, out T value))
{
return value;
}
- if (!allowRecursion && _scopeAccessor.Value.HasScope(key))
- {
- throw new LockRecursionException(LockRecursionExceptionMessage.FormatInvariant(key));
- }
-
- // Get the async (semaphore) locker specific to this key
- using (await KeyedLock.LockAsync("cache:" + key, TimeSpan.FromMinutes(1)))
- {
- if (!TryGet(key, independent, out value))
- {
- var scope = !allowRecursion ? _scopeAccessor.Value.BeginScope(key) : ActionDisposable.Empty;
- using (scope)
- {
- value = await acquirer();
- var dependencies = !allowRecursion ? _scopeAccessor.Value.Current?.Dependencies : (IEnumerable)null;
- Put(key, value, duration, dependencies);
- return value;
- }
- }
- }
-
+ value = await acquirer();
+ Set(key, value, duration.HasValue ? (int)duration.Value.TotalMinutes : (int?)null);
return value;
}
- public void Put(string key, object value, TimeSpan? duration = null, IEnumerable dependencies = null)
+ public ISet GetHashSet(string key, Func> acquirer = null)
{
- _cache.Set(key, value ?? FakeNull, GetCacheItemPolicy(duration, dependencies));
+ throw new NotImplementedException("HashSet not implemented in this cache manager");
}
- public bool Contains(string key)
+ public void Put(string key, object value, TimeSpan? duration = null, IEnumerable dependencies = null)
{
- return _cache.Contains(key);
+ Set(key, value, duration.HasValue ? (int)duration.Value.TotalMinutes : (int?)null);
}
- public void Remove(string key)
+ public void Set(string key, object value, int? cacheTimeInMinutes = null)
{
- _cache.Remove(key);
- }
-
- public IEnumerable Keys(string pattern)
- {
- Guard.NotEmpty(pattern, nameof(pattern));
-
- var keys = _cache.AsParallel().Select(x => x.Key);
-
- if (pattern.IsEmpty() || pattern == "*")
+ var options = new MemoryCacheEntryOptions();
+ if (cacheTimeInMinutes.HasValue)
{
- return keys.ToArray();
+ options.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(cacheTimeInMinutes.Value);
}
-
- var wildcard = new Wildcard(pattern, RegexOptions.IgnoreCase);
- return keys.Where(x => wildcard.IsMatch(x)).ToArray();
+ _cache.Set(key, value ?? FakeNull, options);
}
- public int RemoveByPattern(string pattern)
+ public bool Contains(string key)
{
- lock (_cache)
- {
- var keysToRemove = Keys(pattern);
- int count = 0;
-
- // lock atomic operation
- foreach (string key in keysToRemove)
- {
- _cache.Remove(key);
- count++;
- }
-
- return count;
- }
+ return _cache.TryGetValue(key, out _);
}
- public void Clear()
+ public void Remove(string key)
{
- // Faster way of clearing cache: https://stackoverflow.com/questions/8043381/how-do-i-clear-a-system-runtime-caching-memorycache
- var oldCache = Interlocked.Exchange(ref _cache, CreateCache());
- oldCache.Dispose();
- GC.Collect();
+ _cache.Remove(key);
}
- public virtual ISet GetHashSet(string key, Func> acquirer = null)
+ public IEnumerable Keys(string pattern)
{
- var result = Get(key, () =>
- {
- var set = new MemorySet(this);
- var items = acquirer?.Invoke();
- if (items != null)
- {
- set.AddRange(items);
- }
-
- return set;
- });
-
- return result;
+ // IMemoryCache doesn't support key enumeration
+ // This would need to be tracked separately
+ return Enumerable.Empty();
}
- private CacheItemPolicy GetCacheItemPolicy(TimeSpan? duration, IEnumerable dependencies)
+ public int RemoveByPattern(string pattern)
{
- var absoluteExpiration = ObjectCache.InfiniteAbsoluteExpiration;
-
- if (duration.HasValue)
- {
- absoluteExpiration = DateTime.UtcNow + duration.Value;
- }
-
- var cacheItemPolicy = new CacheItemPolicy
- {
- AbsoluteExpiration = absoluteExpiration,
- SlidingExpiration = ObjectCache.NoSlidingExpiration
- };
-
- if (dependencies != null && dependencies.Any())
- {
- // INFO: we can only depend on existing items, otherwise this entry will be removed immediately.
- dependencies = dependencies.Where(x => x != null && _cache.Contains(x));
- if (dependencies.Any())
- {
- cacheItemPolicy.ChangeMonitors.Add(_cache.CreateCacheEntryChangeMonitor(dependencies));
- }
- }
-
- //cacheItemPolicy.RemovedCallback = OnRemoveEntry;
-
- return cacheItemPolicy;
+ // IMemoryCache doesn't support pattern-based removal
+ // This would need to be tracked separately
+ return 0;
}
- //private void OnRemoveEntry(CacheEntryRemovedArguments args)
- //{
- // if (args.RemovedReason == CacheEntryRemovedReason.ChangeMonitorChanged)
- // {
- // Debug.WriteLine("MEMCACHE: remove depending entry '{0}'.".FormatInvariant(args.CacheItem.Key));
- // }
- //}
-
- protected override void OnDispose(bool disposing)
+ public void Clear()
{
- if (disposing)
- _cache.Dispose();
+ // IMemoryCache doesn't have a Clear method
+ // Would need to track keys separately
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Libraries/SmartStore.Core/Caching/MemoryCacheManager.cs.old b/src/Libraries/SmartStore.Core/Caching/MemoryCacheManager.cs.old
new file mode 100644
index 0000000000..abacce5fd4
--- /dev/null
+++ b/src/Libraries/SmartStore.Core/Caching/MemoryCacheManager.cs.old
@@ -0,0 +1,254 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+// using System.Runtime.Caching; // TODO: Replace with Microsoft.Extensions.Caching.Memory
+using System.Runtime.CompilerServices;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Threading.Tasks;
+using SmartStore.Core.Infrastructure.DependencyManagement;
+using SmartStore.Utilities;
+using SmartStore.Utilities.Threading;
+
+namespace SmartStore.Core.Caching
+{
+ public partial class MemoryCacheManager : DisposableObject, ICacheManager
+ {
+ const string LockRecursionExceptionMessage = "Acquiring identical cache items recursively is not supported. Key: {0}";
+
+ // We put a special string into cache if value is null,
+ // otherwise our 'Contains()' would always return false,
+ // which is bad if we intentionally wanted to save NULL values.
+ public const string FakeNull = "__[NULL]__";
+
+ private readonly Work _scopeAccessor;
+ private MemoryCache _cache;
+
+ public MemoryCacheManager(Work scopeAccessor)
+ {
+ _scopeAccessor = scopeAccessor;
+ _cache = CreateCache();
+ }
+
+ private MemoryCache CreateCache()
+ {
+ return new MemoryCache("SmartStore");
+ }
+
+ public bool IsDistributedCache => false;
+
+ private bool TryGet(string key, bool independent, out T value)
+ {
+ value = default(T);
+
+ object obj = _cache.Get(key);
+
+ if (obj != null)
+ {
+ // Make the parent scope's entry depend on this
+ if (!independent)
+ {
+ _scopeAccessor.Value.PropagateKey(key);
+ }
+
+ if (obj.Equals(FakeNull))
+ {
+ return true;
+ }
+
+ value = (T)obj;
+ return true;
+ }
+
+ return false;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public T Get(string key, bool independent = false)
+ {
+ TryGet(key, independent, out T value);
+ return value;
+ }
+
+ public T Get(string key, Func acquirer, TimeSpan? duration = null, bool independent = false, bool allowRecursion = false)
+ {
+ if (TryGet(key, independent, out T value))
+ {
+ return value;
+ }
+
+ if (!allowRecursion && _scopeAccessor.Value.HasScope(key))
+ {
+ throw new LockRecursionException(LockRecursionExceptionMessage.FormatInvariant(key));
+ }
+
+ // Get the (semaphore) locker specific to this key
+ using (KeyedLock.Lock("cache:" + key, TimeSpan.FromSeconds(5)))
+ {
+ // Atomic operation must be outer locked
+ if (!TryGet(key, independent, out value))
+ {
+ var scope = !allowRecursion ? _scopeAccessor.Value.BeginScope(key) : ActionDisposable.Empty;
+ using (scope)
+ {
+ value = acquirer();
+ var dependencies = !allowRecursion ? _scopeAccessor.Value.Current?.Dependencies : (IEnumerable)null;
+ Put(key, value, duration, dependencies);
+ return value;
+ }
+ }
+ }
+
+ return value;
+ }
+
+ public async Task GetAsync(string key, Func> acquirer, TimeSpan? duration = null, bool independent = false, bool allowRecursion = false)
+ {
+ if (TryGet(key, independent, out T value))
+ {
+ return value;
+ }
+
+ if (!allowRecursion && _scopeAccessor.Value.HasScope(key))
+ {
+ throw new LockRecursionException(LockRecursionExceptionMessage.FormatInvariant(key));
+ }
+
+ // Get the async (semaphore) locker specific to this key
+ using (await KeyedLock.LockAsync("cache:" + key, TimeSpan.FromMinutes(1)))
+ {
+ if (!TryGet(key, independent, out value))
+ {
+ var scope = !allowRecursion ? _scopeAccessor.Value.BeginScope(key) : ActionDisposable.Empty;
+ using (scope)
+ {
+ value = await acquirer();
+ var dependencies = !allowRecursion ? _scopeAccessor.Value.Current?.Dependencies : (IEnumerable)null;
+ Put(key, value, duration, dependencies);
+ return value;
+ }
+ }
+ }
+
+ return value;
+ }
+
+ public void Put(string key, object value, TimeSpan? duration = null, IEnumerable dependencies = null)
+ {
+ _cache.Set(key, value ?? FakeNull, GetCacheItemPolicy(duration, dependencies));
+ }
+
+ public bool Contains(string key)
+ {
+ return _cache.Contains(key);
+ }
+
+ public void Remove(string key)
+ {
+ _cache.Remove(key);
+ }
+
+ public IEnumerable Keys(string pattern)
+ {
+ Guard.NotEmpty(pattern, nameof(pattern));
+
+ var keys = _cache.AsParallel().Select(x => x.Key);
+
+ if (pattern.IsEmpty() || pattern == "*")
+ {
+ return keys.ToArray();
+ }
+
+ var wildcard = new Wildcard(pattern, RegexOptions.IgnoreCase);
+ return keys.Where(x => wildcard.IsMatch(x)).ToArray();
+ }
+
+ public int RemoveByPattern(string pattern)
+ {
+ lock (_cache)
+ {
+ var keysToRemove = Keys(pattern);
+ int count = 0;
+
+ // lock atomic operation
+ foreach (string key in keysToRemove)
+ {
+ _cache.Remove(key);
+ count++;
+ }
+
+ return count;
+ }
+ }
+
+ public void Clear()
+ {
+ // Faster way of clearing cache: https://stackoverflow.com/questions/8043381/how-do-i-clear-a-system-runtime-caching-memorycache
+ var oldCache = Interlocked.Exchange(ref _cache, CreateCache());
+ oldCache.Dispose();
+ GC.Collect();
+ }
+
+ public virtual ISet GetHashSet(string key, Func> acquirer = null)
+ {
+ var result = Get(key, () =>
+ {
+ var set = new MemorySet(this);
+ var items = acquirer?.Invoke();
+ if (items != null)
+ {
+ set.AddRange(items);
+ }
+
+ return set;
+ });
+
+ return result;
+ }
+
+ private CacheItemPolicy GetCacheItemPolicy(TimeSpan? duration, IEnumerable dependencies)
+ {
+ var absoluteExpiration = ObjectCache.InfiniteAbsoluteExpiration;
+
+ if (duration.HasValue)
+ {
+ absoluteExpiration = DateTime.UtcNow + duration.Value;
+ }
+
+ var cacheItemPolicy = new CacheItemPolicy
+ {
+ AbsoluteExpiration = absoluteExpiration,
+ SlidingExpiration = ObjectCache.NoSlidingExpiration
+ };
+
+ if (dependencies != null && dependencies.Any())
+ {
+ // INFO: we can only depend on existing items, otherwise this entry will be removed immediately.
+ dependencies = dependencies.Where(x => x != null && _cache.Contains(x));
+ if (dependencies.Any())
+ {
+ cacheItemPolicy.ChangeMonitors.Add(_cache.CreateCacheEntryChangeMonitor(dependencies));
+ }
+ }
+
+ //cacheItemPolicy.RemovedCallback = OnRemoveEntry;
+
+ return cacheItemPolicy;
+ }
+
+ //private void OnRemoveEntry(CacheEntryRemovedArguments args)
+ //{
+ // if (args.RemovedReason == CacheEntryRemovedReason.ChangeMonitorChanged)
+ // {
+ // Debug.WriteLine("MEMCACHE: remove depending entry '{0}'.".FormatInvariant(args.CacheItem.Key));
+ // }
+ //}
+
+ protected override void OnDispose(bool disposing)
+ {
+ if (disposing)
+ _cache.Dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Libraries/SmartStore.Core/Caching/RequestCache.cs b/src/Libraries/SmartStore.Core/Caching/RequestCache.cs
index 601afc2fef..b0f93d78c5 100644
--- a/src/Libraries/SmartStore.Core/Caching/RequestCache.cs
+++ b/src/Libraries/SmartStore.Core/Caching/RequestCache.cs
@@ -1,3 +1,4 @@
+#if FALSE // TODO: Migrate to ASP.NET Core
using System;
using System.Collections;
using System.Collections.Generic;
@@ -132,3 +133,4 @@ protected override void OnDispose(bool disposing)
}
}
}
+#endif
diff --git a/src/Libraries/SmartStore.Core/Collections/Querystring.cs b/src/Libraries/SmartStore.Core/Collections/Querystring.cs
index 84de3dd797..59dcc3267c 100644
--- a/src/Libraries/SmartStore.Core/Collections/Querystring.cs
+++ b/src/Libraries/SmartStore.Core/Collections/Querystring.cs
@@ -34,7 +34,6 @@ public QueryString(NameValueCollection queryString)
///
/// the string to extract the querystring from
/// a string representing only the querystring
- [SuppressMessage("ReSharper", "StringIndexOfIsCultureSpecific.1")]
public static string ExtractQuerystring(string s)
{
if (!string.IsNullOrEmpty(s))
diff --git a/src/Libraries/SmartStore.Core/Collections/TopologicalSorter.cs b/src/Libraries/SmartStore.Core/Collections/TopologicalSorter.cs
index 1b291e8ac3..8716b3dbce 100644
--- a/src/Libraries/SmartStore.Core/Collections/TopologicalSorter.cs
+++ b/src/Libraries/SmartStore.Core/Collections/TopologicalSorter.cs
@@ -1,3 +1,4 @@
+#if FALSE // TODO: Fix file - corrupted during migration
// CREDITS to Tawani Anyangwe: http://tawani.blogspot.de/2009/02/topological-sorting-and-cyclic.html
using System;
using System.Collections.Generic;
@@ -29,19 +30,15 @@ public static ITopologicSortable[] SortTopological(this ITopologicSortable
for (var i = 0; i < sortedIndexes.Length; i++)
{
- //sortedList[i] = items[sortedIndexes[i]];
- sortedList.Add(items[sortedIndexes[i]]);
}
return sortedList.ToArray();
}
- public static int[] SortIndexesTopological(this ITopologicSortable[] items)
{
return SortIndexesTopological(items, null);
}
- public static int[] SortIndexesTopological(this ITopologicSortable[] items, IEqualityComparer comparer)
{
Guard.NotNull(items, nameof(items));
@@ -218,3 +215,4 @@ private void MoveColLeft(int col, int length)
#endregion
}
}
+#endif
diff --git a/src/Libraries/SmartStore.Core/ComponentModel/FastActivator.cs b/src/Libraries/SmartStore.Core/ComponentModel/FastActivator.cs
index e82db5c515..38f8ab4d1b 100644
--- a/src/Libraries/SmartStore.Core/ComponentModel/FastActivator.cs
+++ b/src/Libraries/SmartStore.Core/ComponentModel/FastActivator.cs
@@ -73,17 +73,14 @@ public static Func