using Microsoft.AspNetCore.Http; using Microsoft.Net.Http.Headers; using Nop.Core; using Nop.Core.Domain.Customers; using Nop.Core.Domain.Stores; using Nop.Core.Infrastructure; using Nop.Data; using Nop.Services.Common; using Nop.Services.Stores; namespace Nop.Web.Framework; /// /// Store context for web application /// public partial class WebStoreContext : IStoreContext { #region Fields protected readonly IGenericAttributeService _genericAttributeService; protected readonly IHttpContextAccessor _httpContextAccessor; protected readonly IRepository _storeRepository; protected readonly IStoreService _storeService; protected Store _cachedStore; protected int? _cachedActiveStoreScopeConfiguration; #endregion #region Ctor /// /// Ctor /// /// Generic attribute service /// HTTP context accessor /// Store repository /// Store service public WebStoreContext(IGenericAttributeService genericAttributeService, IHttpContextAccessor httpContextAccessor, IRepository storeRepository, IStoreService storeService) { _genericAttributeService = genericAttributeService; _httpContextAccessor = httpContextAccessor; _storeRepository = storeRepository; _storeService = storeService; } #endregion #region Properties /// /// Gets the current store /// /// A task that represents the asynchronous operation public virtual async Task GetCurrentStoreAsync() { if (_cachedStore != null) return _cachedStore; //try to determine the current store by HOST header string host = _httpContextAccessor.HttpContext?.Request.Headers[HeaderNames.Host]; var allStores = await _storeService.GetAllStoresAsync(); var store = allStores.FirstOrDefault(s => _storeService.ContainsHostValue(s, host)) ?? allStores.FirstOrDefault(); _cachedStore = store ?? throw new Exception("No store could be loaded"); return _cachedStore; } /// /// Gets the current store /// public virtual Store GetCurrentStore() { if (_cachedStore != null) return _cachedStore; //try to determine the current store by HOST header string host = _httpContextAccessor.HttpContext?.Request.Headers[HeaderNames.Host]; //we cannot call async methods here. otherwise, an application can hang. so it's a workaround to avoid that var allStores = _storeRepository.GetAll(query => { return from s in query orderby s.DisplayOrder, s.Id select s; }, _ => default, includeDeleted: false); var store = allStores.FirstOrDefault(s => _storeService.ContainsHostValue(s, host)) ?? allStores.FirstOrDefault(); _cachedStore = store ?? throw new Exception("No store could be loaded"); return _cachedStore; } /// /// Gets active store scope configuration /// /// A task that represents the asynchronous operation public virtual async Task GetActiveStoreScopeConfigurationAsync() { if (_cachedActiveStoreScopeConfiguration.HasValue) return _cachedActiveStoreScopeConfiguration.Value; //ensure that we have 2 (or more) stores if ((await _storeService.GetAllStoresAsync()).Count > 1) { //do not inject IWorkContext via constructor because it'll cause circular references var currentCustomer = await EngineContext.Current.Resolve().GetCurrentCustomerAsync(); //try to get store identifier from attributes var storeId = await _genericAttributeService .GetAttributeAsync(currentCustomer, NopCustomerDefaults.AdminAreaStoreScopeConfigurationAttribute); _cachedActiveStoreScopeConfiguration = (await _storeService.GetStoreByIdAsync(storeId))?.Id ?? 0; } else _cachedActiveStoreScopeConfiguration = 0; return _cachedActiveStoreScopeConfiguration ?? 0; } #endregion }