Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/Libraries/SmartStore.Core/Async/AsyncRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Hosting;
using Autofac;
using SmartStore.Core.Infrastructure;

Expand Down Expand Up @@ -344,14 +343,14 @@ public override SynchronizationContext CreateCopy()
}
}

internal class BackgroundWorkHost : IRegisteredObject
internal class BackgroundWorkHost
{
private readonly CancellationTokenSource _shutdownCancellationTokenSource = new CancellationTokenSource();
private int _numRunningWorkItems;

public BackgroundWorkHost()
{
HostingEnvironment.RegisterObject(this);
// HostingEnvironment.RegisterObject removed - not available in .NET Core
}

public CancellationTokenSource ShutdownCancellationTokenSource => _shutdownCancellationTokenSource;
Expand Down Expand Up @@ -417,7 +416,7 @@ private void WorkItemComplete(Task work)

private void FinalShutdown()
{
HostingEnvironment.UnregisterObject(this);
// HostingEnvironment.UnregisterObject removed - not available in .NET Core
}

}
Expand Down
94 changes: 43 additions & 51 deletions src/Libraries/SmartStore.Core/Async/LocalAsyncState.cs
Original file line number Diff line number Diff line change
@@ -1,88 +1,67 @@
ο»Ώusing System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Caching;
using System.Threading;
using Microsoft.Extensions.Caching.Memory;

namespace SmartStore.Core.Async
{
public partial class LocalAsyncState : IAsyncState
{
private readonly MemoryCache _states = new MemoryCache("SmartStore.AsyncState.Progress");
private readonly MemoryCache _cancelTokens = new MemoryCache("SmartStore.AsyncState.CancelTokenSources");
private readonly IMemoryCache _states = new MemoryCache(new MemoryCacheOptions());
private readonly IMemoryCache _cancelTokens = new MemoryCache(new MemoryCacheOptions());

public virtual bool Exists<T>(string name = null)
{
var value = GetStateInfo<T>(name);
return value != null && !object.Equals(value.Progress, default(T));

var key = BuildKey<T>(name);
return _states.TryGetValue(key, out var value) && value != null && !object.Equals(((AsyncStateInfo)value).Progress, default(T));
}

public virtual T Get<T>(string name = null)
{
var value = GetStateInfo<T>(name);

if (value != null)
var key = BuildKey<T>(name);
if (_states.TryGetValue(key, out var value) && value is AsyncStateInfo info)
{
return (T)value.Progress;
return (T)info.Progress;
}

return default(T);
}

public virtual IEnumerable<T> GetAll<T>()
{
var keyPrefix = BuildKey<T>(null);
return _states
.Where(x => x.Key.StartsWith(keyPrefix))
.Select(x => x.Value)
.OfType<AsyncStateInfo>()
.Select(x => x.Progress)
.OfType<T>();
// Note: IMemoryCache doesn't support enumeration in .NET Core
// This would need to be tracked separately if needed
return Enumerable.Empty<T>();
}


public virtual void Set<T>(T state, string name = null, bool neverExpires = false)
{
Guard.NotNull(state, nameof(state));

var value = GetStateInfo<T>(name);
var key = BuildKey<T>(name);
var duration = neverExpires ? TimeSpan.Zero : TimeSpan.FromMinutes(15);

if (value != null)
var options = new MemoryCacheEntryOptions();
if (!neverExpires)
{
// exists already, so update
if (state != null)
{
value.Progress = state;
}
options.SlidingExpiration = duration;
}
else
{
// add new entry
var duration = neverExpires ? TimeSpan.Zero : TimeSpan.FromMinutes(15);
var policy = new CacheItemPolicy
{
SlidingExpiration = duration,
Priority = CacheItemPriority.NotRemovable
};
var key = BuildKey<T>(name);

// On expiration or removal: remove corresponding cancel token also.
policy.RemovedCallback = (x) => OnRemoveCancelTokenSource(key);
options.Priority = CacheItemPriority.NeverRemove;
options.RegisterPostEvictionCallback((k, v, r, s) => OnRemoveCancelTokenSource((string)k));

_states.Set(key, new AsyncStateInfo { Progress = state, Duration = duration }, policy);
}
_states.Set(key, new AsyncStateInfo { Progress = state, Duration = duration }, options);
}

public virtual void Update<T>(Action<T> update, string name = null)
{
Guard.NotNull(update, nameof(update));

var value = GetStateInfo<T>(name);

if (value != null)
var key = BuildKey<T>(name);
if (_states.TryGetValue(key, out var value) && value is AsyncStateInfo info)
{
var state = (T)value.Progress;
var state = (T)info.Progress;
if (state != null)
{
update(state);
Expand All @@ -108,7 +87,8 @@ public virtual bool Remove<T>(string name = null)

protected virtual bool OnRemoveStateInfo(string key)
{
return _states.Remove(key) != null;
_states.Remove(key);
return true;
}

public virtual bool RemoveCancelTokenSource<T>(string name = null)
Expand All @@ -120,10 +100,9 @@ protected virtual bool OnRemoveCancelTokenSource(string key, bool successive = f
{
Guard.NotEmpty(key, nameof(key));

var token = _cancelTokens.Remove(key) as CancellationTokenSource;

if (token != null)
if (_cancelTokens.TryGetValue(key, out var value) && value is CancellationTokenSource token)
{
_cancelTokens.Remove(key);
token.Dispose();
return true;
}
Expand All @@ -141,7 +120,12 @@ protected virtual CancellationTokenSource OnGetCancelTokenSource(string key, boo
{
Guard.NotEmpty(key, nameof(key));

return _cancelTokens.Get(key) as CancellationTokenSource;
if (_cancelTokens.TryGetValue(key, out var value) && value is CancellationTokenSource token)
{
return token;
}

return null;
}

public virtual void SetCancelTokenSource<T>(CancellationTokenSource cancelTokenSource, string name = null)
Expand All @@ -155,9 +139,12 @@ public virtual void SetCancelTokenSource<T>(CancellationTokenSource cancelTokenS
OnRemoveCancelTokenSource(key);
}

var policy = new CacheItemPolicy { Priority = CacheItemPriority.NotRemovable };
var options = new MemoryCacheEntryOptions
{
Priority = CacheItemPriority.NeverRemove
};

_cancelTokens.Set(key, cancelTokenSource, policy);
_cancelTokens.Set(key, cancelTokenSource, options);
}

public bool Cancel<T>(string name = null)
Expand All @@ -183,7 +170,12 @@ protected virtual bool OnCancel(string key, bool successive = false)

protected virtual AsyncStateInfo GetStateInfo<T>(string name = null)
{
return _states.Get(BuildKey<T>(name)) as AsyncStateInfo;
var key = BuildKey<T>(name);
if (_states.TryGetValue(key, out var value) && value is AsyncStateInfo info)
{
return info;
}
return null;
}

protected string BuildKey<T>(string name)
Expand Down
20 changes: 8 additions & 12 deletions src/Libraries/SmartStore.Core/BaseEntity.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -30,18 +29,15 @@ 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
var type = GetType();

// In EF Core, proxy types have a namespace starting with "Castle.Proxies"
if (type.Namespace != null && type.Namespace.StartsWith("Castle.Proxies"))
{
return type.BaseType;
}

return ObjectContext.GetObjectType(GetType());
return type;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Caching;
using Microsoft.Extensions.Caching.Memory;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using System.Threading;
Expand Down
15 changes: 15 additions & 0 deletions src/Libraries/SmartStore.Core/Compatibility/AutofacIntegration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Compatibility stubs for Autofac.Integration.Mvc
// TODO: Replace with proper Autofac ASP.NET Core integration

using System;
using Autofac;

namespace Autofac.Integration.Mvc
{
public interface ILifetimeScopeProvider
{
ILifetimeScope ApplicationContainer { get; }
ILifetimeScope GetLifetimeScope(Action<ContainerBuilder> configurationAction);
void EndLifetimeScope();
}
}
46 changes: 46 additions & 0 deletions src/Libraries/SmartStore.Core/Compatibility/Cache.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Compatibility stub for System.Web.Caching.Cache
// TODO: Replace with Microsoft.Extensions.Caching.Memory

using Microsoft.Extensions.Caching.Memory;

namespace System.Web.Caching
{
public class Cache
{
private readonly IMemoryCache _cache;

public Cache()
{
_cache = new MemoryCache(new MemoryCacheOptions());
}

public object this[string key]
{
get => _cache.TryGetValue(key, out var value) ? value : null;
set => _cache.Set(key, value);
}

public object Get(string key) => this[key];

public void Insert(string key, object value)
{
_cache.Set(key, value);
}

public void Insert(string key, object value, CacheDependency dependencies)
{
_cache.Set(key, value);
}

public object Remove(string key)
{
var value = this[key];
_cache.Remove(key);
return value;
}
}

public class CacheDependency
{
}
}
42 changes: 42 additions & 0 deletions src/Libraries/SmartStore.Core/Compatibility/HtmlTextWriter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Compatibility stub for System.Web.UI.HtmlTextWriter
// TODO: Replace with proper HTML generation

using System.IO;

namespace System.Web.UI
{
public class HtmlTextWriter : TextWriter
{
private readonly TextWriter _writer;

public HtmlTextWriter(TextWriter writer)
{
_writer = writer;
}

public override System.Text.Encoding Encoding => _writer.Encoding;

public override void Write(char value) => _writer.Write(value);
public override void Write(string value) => _writer.Write(value);

public void WriteAttribute(string name, string value)
{
_writer.Write($" {name}=\"{value}\"");
}

public void WriteBeginTag(string tagName)
{
_writer.Write($"<{tagName}");
}

public void WriteEndTag(string tagName)
{
_writer.Write($"</{tagName}>");
}

public void WriteFullBeginTag(string tagName)
{
_writer.Write($"<{tagName}>");
}
}
}
29 changes: 29 additions & 0 deletions src/Libraries/SmartStore.Core/Compatibility/HttpContextBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Compatibility stub for System.Web.HttpContextBase
// TODO: Replace with proper ASP.NET Core HttpContext usage

using System.Collections.Generic;
using Microsoft.AspNetCore.Http;

namespace System.Web
{
public abstract class HttpContextBase
{
public virtual HttpContext Context { get; set; }
public virtual HttpRequest Request => Context?.Request;
public virtual HttpResponse Response => Context?.Response;
public virtual IDictionary<object, object> Items => Context?.Items;

public virtual object GetService(Type serviceType)
{
return Context?.RequestServices?.GetService(serviceType);
}
}

public class HttpContextWrapper : HttpContextBase
{
public HttpContextWrapper(HttpContext context)
{
Context = context;
}
}
}
Loading