using System; using System.Collections.Concurrent; using Abp.Collections.Extensions; using Castle.Core.Logging; using JetBrains.Annotations; namespace Abp.Runtime.Remoting { public class DataContextAmbientScopeProvider : IAmbientScopeProvider { public ILogger Logger { get; set; } private static readonly ConcurrentDictionary ScopeDictionary = new ConcurrentDictionary(); private readonly IAmbientDataContext _dataContext; public DataContextAmbientScopeProvider([NotNull] IAmbientDataContext dataContext) { Check.NotNull(dataContext, nameof(dataContext)); _dataContext = dataContext; Logger = NullLogger.Instance; } public T GetValue(string contextKey) { var item = GetCurrentItem(contextKey); if (item == null) { return default(T); } return item.Value; } public IDisposable BeginScope(string contextKey, T value) { var item = new ScopeItem(value, GetCurrentItem(contextKey)); if (!ScopeDictionary.TryAdd(item.Id, item)) { throw new AbpException("Can not add item! ScopeDictionary.TryAdd returns false!"); } _dataContext.SetData(contextKey, item.Id); return new DisposeAction(() => { ScopeDictionary.TryRemove(item.Id, out item); if (item.Outer == null) { _dataContext.SetData(contextKey, null); return; } _dataContext.SetData(contextKey, item.Outer.Id); }); } private ScopeItem GetCurrentItem(string contextKey) { var objKey = _dataContext.GetData(contextKey) as string; return objKey != null ? ScopeDictionary.GetOrDefault(objKey) : null; } private class ScopeItem { public string Id { get; } public ScopeItem Outer { get; } public T Value { get; } public ScopeItem(T value, ScopeItem outer = null) { Id = Guid.NewGuid().ToString(); Value = value; Outer = outer; } } } }