using System.Transactions; using AyCode.Core.Consts; using AyCode.Core.Helpers; using AyCode.Core.Loggers; using AyCode.Utils.Extensions; using Mango.Nop.Core.Interfaces; using Mango.Nop.Core.Loggers; using Mango.Nop.Services; using Nop.Core.Caching; using Nop.Core.Domain.Catalog; using Nop.Core.Domain.Orders; using Nop.Data; namespace Mango.Nop.Core.Repositories; public abstract class MgDbContextBase : IMgDbContextBase { //TODO: ez itt nem ay igazi, kitalálni vmit! - J. private readonly CacheKey _auctionAllKey = new("Nop.auction.all-{0}", AUCTION_PATTERN_KEY); public const string AUCTION_PATTERN_KEY = "Nop.auction."; protected readonly IMgLockService LockService; public ILogger Logger { get; init; } public INopDataProvider DataProvider { get; init; } public IRepository Orders { get; set; } public IRepository OrderItems { get; set; } public IRepository Products { get; set; } //public IHttpContextAccessor HttpContextAccessor { get; init; } public MgDbContextBase(IRepository productRepository, IRepository orderRepository, IRepository orderItemRepository, INopDataProvider dataProvider, IMgLockService lockService, ILogger logger) { LockService = lockService; Logger = logger;// new Logger(logWriters.ToArray()); DataProvider = dataProvider; Products = productRepository; Orders = orderRepository; OrderItems = orderItemRepository; } private static TransactionScope CreateTransactionScope(TransactionScopeOption transactionScopeOption = TransactionScopeOption.Required) { //TransactionManager.ImplicitDistributedTransactions = true; var transactionOptions = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted, Timeout = TransactionManager.DefaultTimeout }; return new TransactionScope(transactionScopeOption, transactionOptions, TransactionScopeAsyncFlowOption.Enabled); //return new TransactionScope(TransactionScopeOption.Required, TransactionScopeAsyncFlowOption.Enabled); } public bool Transaction(Func callbackTransactionBody, bool throwException = false) => TransactionInner(callbackTransactionBody, throwException); /// /// Using LoskService, global lock! /// /// /// /// public bool TransactionSafe(Func callbackTransactionBody, bool throwException = false) { using (LockService.SemaphoreSlim.UseWait()) { return TransactionInner(callbackTransactionBody, throwException); } } public Task TransactionAsync(Func> callbackTransactionBody, bool throwException = false) => TaskHelper.ToThreadPoolTask(() => TransactionInnerAsync(callbackTransactionBody, throwException)); /// /// Using LoskService, global lock! /// /// /// /// public Task TransactionSafeAsync(Func> callbackTransactionBody, bool throwException = false) { return TaskHelper.ToThreadPoolTask(async () => { using (await LockService.SemaphoreSlim.UseWaitAsync()) { return await TransactionInnerAsync(callbackTransactionBody, throwException); } }); } private async Task TransactionInnerAsync(Func> callbackTransactionBody, bool throwException = false) { bool result; try { using (var transaction = CreateTransactionScope())// new TransactionScope( /*TransactionScopeOption.RequiresNew, */TransactionScopeAsyncFlowOption.Enabled)) { result = await callbackTransactionBody(transaction); if (result) transaction.Complete(); } if (!result) Logger.Warning($"TransactionInnerAsync({this}) transaction ROLLBACK!"); } catch (Exception ex) { if (throwException) throw; result = false; Logger.Error($"TransactionInnerAsync({this}) transaction ROLLBACK! ex: {ex.Message}{AcEnv.NL}", ex); } return result; } private bool TransactionInner(Func callbackTransactionBody, bool throwException = false) { bool result; try { using(var transaction = CreateTransactionScope()) //new TransactionScope( /*TransactionScopeOption.RequiresNew, */TransactionScopeAsyncFlowOption.Enabled) { result = callbackTransactionBody(transaction); if (result) transaction.Complete(); } if (!result) Logger.Warning($"TransactionInner({this}) transaction ROLLBACK!"); } catch (Exception ex) { if (throwException) throw; result = false; Logger.Error($"TransactionInnerAsync({this}) transaction error! ex: {ex.Message}{AcEnv.NL}", ex); } return result; } public override string ToString() { return GetType().Name; } }