public static Task WithUserQuotesAsync(this IWorkContextBuilder builder) { if (builder.WorkContext.CurrentUser != null) { var serviceProvider = builder.HttpContext.RequestServices; var quoteService = serviceProvider.GetRequiredService <IQuoteService>(); Func <int, int, IEnumerable <SortInfo>, NameValueCollection, IPagedList <Model.Quote.QuoteRequest> > factory = (pageNumber, pageSize, sortInfos, @params) => { var quoteSearchCriteria = new Model.Quote.QuoteSearchCriteria { PageNumber = pageNumber, PageSize = pageSize, Sort = sortInfos?.ToString(), CustomerId = builder.WorkContext.CurrentUser.Id }; if (@params != null) { quoteSearchCriteria.CopyFrom(@params); } return(quoteService.SearchQuotes(quoteSearchCriteria)); }; return(builder.WithUserQuotesAsync(new MutablePagedList <Model.Quote.QuoteRequest>(factory, 1, Model.Quote.QuoteSearchCriteria.DefaultPageSize))); } return(Task.CompletedTask); }
public static Task WithUserOrdersAsync(this IWorkContextBuilder builder) { if (builder.WorkContext.CurrentUser != null) { var serviceProvider = builder.HttpContext.RequestServices; var orderService = serviceProvider.GetRequiredService <ICustomerOrderService>(); Func <int, int, IEnumerable <SortInfo>, NameValueCollection, IPagedList <CustomerOrder> > factory = (pageNumber, pageSize, sortInfos, @params) => { var orderSearchcriteria = new OrderSearchCriteria { CustomerId = builder.WorkContext.CurrentUser.Id, PageNumber = pageNumber, PageSize = pageSize, Sort = sortInfos?.ToString() }; if (@params != null) { orderSearchcriteria.CopyFrom(@params); } var result = orderService.SearchOrders(orderSearchcriteria); return(new StaticPagedList <CustomerOrder>(result, pageNumber, pageSize, result.Count)); }; return(builder.WithUserOrdersAsync(new MutablePagedList <CustomerOrder>(factory, 1, OrderSearchCriteria.DefaultPageSize))); } return(Task.CompletedTask); }
public static Task WithStoresAsync(this IWorkContextBuilder builder, IEnumerable <Store> stores, string defaultStoreId) { if (stores == null) { throw new NoStoresException(); } builder.WorkContext.AllStores = stores.ToArray(); var currentStore = builder.HttpContext.GetCurrentStore(stores, defaultStoreId); //Very important workaround. If left Null or Empty as Url for default store with condition of multiple stores present, will be generated a relative url '/store_name/' instead of // '/' thats can leads to invalid urls to default store and other issue with <base href=""> that contains invalid relative url if (defaultStoreId != null && string.IsNullOrEmpty(currentStore.Url) && currentStore.Id.EqualsInvariant(defaultStoreId)) { currentStore.Url = "/"; } builder.WorkContext.CurrentStore = currentStore; builder.WorkContext.CurrentLanguage = builder.HttpContext.GetCurrentLanguage(builder.WorkContext.CurrentStore); // SEO for category, product and blogs is set inside corresponding controllers // there we default SEO for requested store var seoInfo = builder.WorkContext.CurrentStore.SeoInfos?.FirstOrDefault(x => x.Language == builder.WorkContext.CurrentLanguage); if (seoInfo != null && builder.WorkContext.RequestUrl != null) { var htmlEncoder = builder.HttpContext.RequestServices.GetRequiredService <HtmlEncoder>(); seoInfo.Slug = htmlEncoder.Encode(builder.WorkContext.RequestUrl.ToString()); builder.WorkContext.CurrentPageSeo = seoInfo; } return(Task.CompletedTask); }
public static Task WithVendorsAsync(this IWorkContextBuilder builder, Store store, Language language) { var serviceProvider = builder.HttpContext.RequestServices; var customerService = serviceProvider.GetRequiredService <IMemberService>(); var catalogService = serviceProvider.GetRequiredService <ICatalogService>(); Func <int, int, IEnumerable <SortInfo>, IPagedList <Vendor> > factory = (pageNumber, pageSize, sortInfos) => { var vendors = customerService.SearchVendors(store, language, null, pageNumber, pageSize, sortInfos); foreach (var vendor in vendors) { vendor.Products = new MutablePagedList <Product>((pageNumber2, pageSize2, sortInfos2) => { var vendorProductsSearchCriteria = new ProductSearchCriteria { VendorId = vendor.Id, PageNumber = pageNumber2, PageSize = pageSize2, ResponseGroup = builder.WorkContext.CurrentProductSearchCriteria.ResponseGroup & ~ItemResponseGroup.ItemWithVendor, SortBy = SortInfo.ToString(sortInfos2), }; var searchResult = catalogService.SearchProducts(vendorProductsSearchCriteria); return(searchResult.Products); }, 1, ProductSearchCriteria.DefaultPageSize); } return(vendors); }; return(builder.WithVendorsAsync(() => new MutablePagedList <Vendor>(factory, 1, VendorSearchCriteria.DefaultPageSize))); }
public static async Task WithCountriesAsync(this IWorkContextBuilder builder) { var serviceProvider = builder.HttpContext.RequestServices; var countryService = serviceProvider.GetRequiredService <ICountriesService>(); var countries = await countryService.GetCountriesAsync(); await builder.WithCountriesAsync(countries); }
public static Task WithUserContactAsync(this IWorkContextBuilder builder, Func <Contact> factory) { builder.WorkContext.CurrentUser.Contact = new Lazy <Contact>(() => { return(factory()); }); return(Task.CompletedTask); }
public static Task WithPricelistsAsync(this IWorkContextBuilder builder, IList <Pricelist> pricelists) { if (pricelists == null) { throw new ArgumentNullException(nameof(pricelists)); } builder.WorkContext.CurrentPricelists = pricelists; return(Task.CompletedTask); }
public static async Task WithCurrentUserAsync(this IWorkContextBuilder builder) { var serviceProvider = builder.HttpContext.RequestServices; var signInManager = serviceProvider.GetRequiredService <SignInManager <User> >(); // Gets the collection of external login providers var externalAuthTypes = (await signInManager.GetExternalAuthenticationSchemesAsync()).ToList(); builder.WorkContext.ExternalLoginProviders = externalAuthTypes.Select(at => new LoginProvider { AuthenticationType = at.Name, Caption = at.DisplayName, }).ToList(); var user = new User { Id = builder.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier), UserName = builder.HttpContext.User.FindFirstValue(ClaimTypes.Name) }; var identity = builder.HttpContext.User.Identity; if (identity.IsAuthenticated) { user = await signInManager.UserManager.FindByNameAsync(identity.Name); //User has been removed from storage or current store is not allowed for signed in user //need to do sign out if (user == null || !user.AllowedStores.Contains(builder.WorkContext.CurrentStore.Id)) { await signInManager.SignOutAsync(); user = null; } } if (user == null || user.IsTransient()) { user = new User { Id = Guid.NewGuid().ToString(), UserName = StorefrontClaims.AnonymousUsername, }; //Workaround: Do not sign out for js map requests they are always coming without authentication if (!builder.HttpContext.Request.Path.Value.EndsWith(".map")) { //Sign-in anonymous user await signInManager.SignInAsync(user, false); } } //Restore some properties from claims user.OperatorUserId = builder.HttpContext.User.FindFirstValue(StorefrontClaims.OperatorUserIdClaimType); user.OperatorUserName = builder.HttpContext.User.FindFirstValue(StorefrontClaims.OperatorUserNameClaimType); user.SelectedCurrencyCode = builder.HttpContext.User.FindFirstValue(StorefrontClaims.CurrencyClaimType); builder.WorkContext.CurrentUser = user; }
public static async Task WithPricelistsAsync(this IWorkContextBuilder builder) { var serviceProvider = builder.HttpContext.RequestServices; var pricingService = serviceProvider.GetRequiredService <IPricingService>(); var pricelists = await pricingService.EvaluatePricesListsAsync(builder.WorkContext.ToPriceEvaluationContext(), builder.WorkContext); await builder.WithPricelistsAsync(pricelists); }
public static async Task WithCurrentUserAsync(this IWorkContextBuilder builder) { var serviceProvider = builder.HttpContext.RequestServices; var signInManager = serviceProvider.GetRequiredService <SignInManager <User> >(); // Gets the collection of external login providers var externalAuthTypes = (await signInManager.GetExternalAuthenticationSchemesAsync()).ToList(); builder.WorkContext.ExternalLoginProviders = externalAuthTypes.Select(at => new LoginProvider { AuthenticationType = at.Name, Caption = at.DisplayName, }).ToList(); var user = await signInManager.UserManager.GetUserAsync(builder.HttpContext.User); //User doesn't have permissions for login to current store //need to do sign out if (user != null && !new CanUserLoginToStoreSpecification(user).IsSatisfiedBy(builder.WorkContext.CurrentStore)) { await signInManager.SignOutAsync(); user = null; } if (user != null && new IsUserSuspendedSpecification().IsSatisfiedBy(user)) { await signInManager.SignOutAsync(); user = null; } //Login as a new anonymous user if (user == null || user.IsTransient()) { user = new User { Id = Guid.NewGuid().ToString(), SecurityStamp = Guid.NewGuid().ToString(), UserName = SecurityConstants.AnonymousUsername, }; //Workaround: Do not sign out for js map requests they are always coming without authentication if (!builder.HttpContext.Request.Path.Value.EndsWith(".map")) { //Sign-in anonymous user await signInManager.SignInAsync(user, new AuthenticationProperties { IsPersistent = false, ExpiresUtc = DateTimeOffset.Now.AddDays(30) }); //https://github.com/aspnet/Security/issues/1131 //the sign in operation doesn't change the current request user principal. //That only happens on incoming requests once the cookie or bearer token (or whatever thing the type of auth requires to create an identity) is set. //Need to manually set User in the HttpContext to avoid issues such like Antiforegery token generation for undefined user for the current request builder.HttpContext.User = await signInManager.ClaimsFactory.CreateAsync(user); } } builder.WorkContext.CurrentUser = user; }
public static Task WithStoresAsync(this IWorkContextBuilder builder, IEnumerable <Store> stores, string defaultStoreId) { if (stores == null) { throw new NoStoresException(); } builder.WorkContext.AllStores = stores.ToArray(); builder.WorkContext.CurrentStore = builder.HttpContext.GetCurrentStore(stores, defaultStoreId); builder.WorkContext.CurrentLanguage = builder.HttpContext.GetCurrentLanguage(builder.WorkContext.CurrentStore); return(Task.CompletedTask); }
public static Task WithUserContactAsync(this IWorkContextBuilder builder) { if (builder.WorkContext.CurrentUser != null && builder.WorkContext.CurrentUser.ContactId != null) { var serviceProvider = builder.HttpContext.RequestServices; var memberService = serviceProvider.GetRequiredService <IMemberService>(); return(builder.WithUserContactAsync(() => memberService.GetContactById(builder.WorkContext.CurrentUser.ContactId))); } return(Task.CompletedTask); }
public static Task WithCurrenciesAsync(this IWorkContextBuilder builder, IList <Currency> availCurrencies, Store store) { if (availCurrencies == null) { throw new ArgumentNullException(nameof(availCurrencies)); } //Filter all avail currencies, leave only currencies define for store var storeCurrencies = availCurrencies.Where(x => store.CurrenciesCodes.Any(y => x.Equals(y))).ToList(); builder.WorkContext.AllCurrencies = storeCurrencies; builder.WorkContext.CurrentCurrency = builder.HttpContext.GetCurrentCurrency(availCurrencies, store); return(Task.CompletedTask); }
public static Task WithPricelistsAsync(this IWorkContextBuilder builder) { var serviceProvider = builder.HttpContext.RequestServices; var pricingService = serviceProvider.GetRequiredService <IPricingService>(); Func <int, int, IEnumerable <SortInfo>, IPagedList <Pricelist> > factory = (pageNumber, pageSize, sortInfos) => { var pricelists = pricingService.EvaluatePricesLists(builder.WorkContext.ToPriceEvaluationContext(null), builder.WorkContext); return(new StaticPagedList <Pricelist>(pricelists, pageNumber, pageSize, pricelists.Count)); }; return(builder.WithPricelistsAsync(new MutablePagedList <Pricelist>(factory, 1, int.MaxValue))); }
public static Task WithQuotesAsync(this IWorkContextBuilder builder, Store store, User user, Currency currency, Language language) { var serviceProvider = builder.HttpContext.RequestServices; var quoteRequestBuilder = serviceProvider.GetRequiredService <IQuoteRequestBuilder>(); Func <Model.Quote.QuoteRequest> factory = () => { quoteRequestBuilder.GetOrCreateNewTransientQuoteRequestAsync(store, user, language, currency).GetAwaiter().GetResult(); return(quoteRequestBuilder.QuoteRequest); }; return(builder.WithQuotesAsync(factory)); }
public static Task WithQuotesAsync(this IWorkContextBuilder builder, Store store, User user, Currency currency, Language language) { var serviceProvider = builder.HttpContext.RequestServices; var quoteRequestBuilder = serviceProvider.GetRequiredService <IQuoteRequestBuilder>(); Func <Model.Quote.QuoteRequest> factory = () => { Task.Factory.StartNew(() => quoteRequestBuilder.GetOrCreateNewTransientQuoteRequestAsync(store, user, language, currency), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap().GetAwaiter().GetResult(); return(quoteRequestBuilder.QuoteRequest); }; return(builder.WithQuotesAsync(factory)); }
public static Task WithFulfillmentCentersAsync(this IWorkContextBuilder builder) { var serviceProvider = builder.HttpContext.RequestServices; var inventoryService = serviceProvider.GetRequiredService <IInventoryService>(); Func <int, int, IEnumerable <SortInfo>, IPagedList <FulfillmentCenter> > factory = (pageNumber, pageSize, sortInfos) => { return(inventoryService.SearchFulfillmentCenters(new FulfillmentCenterSearchCriteria { PageNumber = pageNumber, PageSize = pageNumber, Sort = SortInfo.ToString(sortInfos) })); }; return(builder.WithFulfillmentCentersAsync(() => new MutablePagedList <FulfillmentCenter>(factory, 1, FulfillmentCenterSearchCriteria.DefaultPageSize))); }
public static async Task WithCurrenciesAsync(this IWorkContextBuilder builder, Language language, Store store) { if (language == null) { throw new ArgumentNullException(nameof(language)); } var serviceProvider = builder.HttpContext.RequestServices; var currencyService = serviceProvider.GetRequiredService <ICurrencyService>(); var currencies = await currencyService.GetAllCurrenciesAsync(language); await builder.WithCurrenciesAsync(currencies, store); }
public static async Task WithStoresAsync(this IWorkContextBuilder builder, string defaultStoreId) { var serviceProvider = builder.HttpContext.RequestServices; var storeService = serviceProvider.GetRequiredService <IStoreService>(); var stores = await storeService.GetAllStoresAsync(); if (stores.IsNullOrEmpty()) { throw new NoStoresException(); } await builder.WithStoresAsync(stores, defaultStoreId); }
public static Task WithDefaultShoppingCartAsync(this IWorkContextBuilder builder, string cartName, Store store, User user, Currency currency, Language language) { var serviceProvider = builder.HttpContext.RequestServices; var cartBuilder = serviceProvider.GetRequiredService <ICartBuilder>(); Func <Model.Cart.ShoppingCart> factory = () => { cartBuilder.LoadOrCreateNewTransientCart(cartName, store, user, language, currency); return(cartBuilder.Cart); }; return(builder.WithDefaultShoppingCartAsync(factory)); }
public static async Task WithCurrentUserAsync(this IWorkContextBuilder builder) { var serviceProvider = builder.HttpContext.RequestServices; var signInManager = serviceProvider.GetRequiredService <SignInManager <User> >(); // Gets the collection of external login providers var externalAuthTypes = (await signInManager.GetExternalAuthenticationSchemesAsync()).ToList(); builder.WorkContext.ExternalLoginProviders = externalAuthTypes.Select(at => new LoginProvider { AuthenticationType = at.Name, Caption = at.DisplayName, }).ToList(); var user = await signInManager.UserManager.GetUserAsync(builder.HttpContext.User); //User doesn't have permissions for login to current store //need to do sign out if (user != null && !new CanUserLoginToStoreSpecification(user).IsSatisfiedBy(builder.WorkContext.CurrentStore)) { await signInManager.SignOutAsync(); user = null; } //Login as a new anonymous user if (user == null || user.IsTransient()) { user = new User { Id = Guid.NewGuid().ToString(), SecurityStamp = Guid.NewGuid().ToString(), UserName = SecurityConstants.AnonymousUsername, }; //Workaround: Do not sign out for js map requests they are always coming without authentication if (!builder.HttpContext.Request.Path.Value.EndsWith(".map")) { //Sign-in anonymous user await signInManager.SignInAsync(user, false); } } builder.WorkContext.CurrentUser = user; }
public static Task WithPricelistsAsync(this IWorkContextBuilder builder) { var serviceProvider = builder.HttpContext.RequestServices; var pricingService = serviceProvider.GetRequiredService <IPricingService>(); Func <int, int, IEnumerable <SortInfo>, IPagedList <Pricelist> > factory = (pageNumber, pageSize, sortInfos) => { IList <Pricelist> pricelists = new List <Pricelist>(); //Do not evaluate price lists for anonymous user if (builder.WorkContext.CurrentUser.IsRegisteredUser) { var priceListEvaluationContext = builder.WorkContext.ToPriceEvaluationContext(null); priceListEvaluationContext.CertainDate = DateTime.UtcNow; pricelists = pricingService.EvaluatePricesLists(priceListEvaluationContext, builder.WorkContext); } return(new StaticPagedList <Pricelist>(pricelists, pageNumber, pageSize, pricelists.Count)); }; return(builder.WithPricelistsAsync(new MutablePagedList <Pricelist>(factory, 1, int.MaxValue))); }
public static Task WithMenuLinksAsync(this IWorkContextBuilder builder, Store store, Language language) { if (store == null) { throw new ArgumentNullException(nameof(store)); } if (language == null) { throw new ArgumentNullException(nameof(language)); } var serviceProvider = builder.HttpContext.RequestServices; var linkListService = serviceProvider.GetRequiredService <IMenuLinkListService>(); Func <int, int, IEnumerable <SortInfo>, IPagedList <MenuLinkList> > factory = (pageNumber, pageSize, sorInfos) => { var linkLists = Task.Factory.StartNew(() => linkListService.LoadAllStoreLinkListsAsync(store, language), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap().GetAwaiter().GetResult(); return(new StaticPagedList <MenuLinkList>(linkLists, pageNumber, pageSize, linkLists.Count())); }; return(builder.WithMenuLinksAsync(() => new MutablePagedList <MenuLinkList>(factory, 1, 20))); }
public static Task WithMenuLinksAsync(this IWorkContextBuilder builder, Store store, Language language) { if (store == null) { throw new ArgumentNullException(nameof(store)); } if (language == null) { throw new ArgumentNullException(nameof(language)); } var serviceProvider = builder.HttpContext.RequestServices; var linkListService = serviceProvider.GetRequiredService <IMenuLinkListService>(); Func <int, int, IEnumerable <SortInfo>, IPagedList <MenuLinkList> > factory = (pageNumber, pageSize, sorInfos) => { var linkLists = linkListService.LoadAllStoreLinkLists(store, language); return(new StaticPagedList <MenuLinkList>(linkLists, pageNumber, pageSize, linkLists.Count())); }; return(builder.WithMenuLinksAsync(new MutablePagedList <MenuLinkList>(factory, 1, 20))); }
public static Task WithUserSubscriptionsAsync(this IWorkContextBuilder builder) { if (builder.WorkContext.CurrentUser != null) { var serviceProvider = builder.HttpContext.RequestServices; var subscriptionService = serviceProvider.GetRequiredService <ISubscriptionService>(); Func <int, int, IEnumerable <SortInfo>, IPagedList <Subscription> > factory = (pageNumber, pageSize, sortInfos) => { var subscriptionSearchCriteria = new SubscriptionSearchCriteria { PageNumber = pageNumber, PageSize = pageSize, Sort = sortInfos?.ToString(), CustomerId = builder.WorkContext.CurrentUser.Id }; return(subscriptionService.SearchSubscription(subscriptionSearchCriteria)); }; return(builder.WithUserSubscriptionsAsync(() => new MutablePagedList <Subscription>(factory, 1, SubscriptionSearchCriteria.DefaultPageSize))); } return(Task.CompletedTask); }
public static Task WithStoresAsync(this IWorkContextBuilder builder, IEnumerable <Store> stores, string defaultStoreId) { if (stores == null) { throw new NoStoresException(); } builder.WorkContext.AllStores = stores.ToArray(); builder.WorkContext.CurrentStore = builder.HttpContext.GetCurrentStore(stores, defaultStoreId); builder.WorkContext.CurrentLanguage = builder.HttpContext.GetCurrentLanguage(builder.WorkContext.CurrentStore); // SEO for category, product and blogs is set inside corresponding controllers // there we default SEO for requested store var seoInfo = builder.WorkContext.CurrentStore.SeoInfos?.FirstOrDefault(x => x.Language == builder.WorkContext.CurrentLanguage); if (seoInfo != null && builder.WorkContext.RequestUrl != null) { var htmlEncoder = builder.HttpContext.RequestServices.GetRequiredService <HtmlEncoder>(); seoInfo.Slug = htmlEncoder.Encode(builder.WorkContext.RequestUrl.ToString()); builder.WorkContext.CurrentPageSeo = seoInfo; } return(Task.CompletedTask); }
public static Task WithBlogsAsync(this IWorkContextBuilder builder, Store store, Language language) { if (store == null) { throw new ArgumentNullException(nameof(store)); } if (language == null) { throw new ArgumentNullException(nameof(language)); } var serviceProvider = builder.HttpContext.RequestServices; var staticContentService = serviceProvider.GetRequiredService <IStaticContentService>(); Func <int, int, IEnumerable <SortInfo>, IPagedList <Blog> > factory = (pageNumber, pageSize, sorInfos) => { //TODO: performance and DDD specification instead if statements var contentItems = staticContentService.LoadStoreStaticContent(store).Where(x => x.Language.IsInvariant || x.Language == language); var blogs = contentItems.OfType <Blog>().ToArray(); var blogArticlesGroup = contentItems.OfType <BlogArticle>().GroupBy(x => x.BlogName, x => x).ToList(); foreach (var blog in blogs) { var blogArticles = blogArticlesGroup.FirstOrDefault(x => string.Equals(x.Key, blog.Name, StringComparison.OrdinalIgnoreCase)); if (blogArticles != null) { blog.Articles = new MutablePagedList <BlogArticle>(blogArticles); } } return(new StaticPagedList <Blog>(blogs, pageNumber, pageSize, blogs.Count())); }; // Initialize blogs search criteria builder.WorkContext.CurrentBlogSearchCritera = new BlogSearchCriteria(builder.WorkContext.QueryString); return(builder.WithBlogsAsync(() => new MutablePagedList <Blog>(factory, 1, 20))); }
public static Task WithPagesAsync(this IWorkContextBuilder builder, Store store, Language language) { if (store == null) { throw new ArgumentNullException(nameof(store)); } if (language == null) { throw new ArgumentNullException(nameof(language)); } var serviceProvider = builder.HttpContext.RequestServices; var staticContentService = serviceProvider.GetRequiredService <IStaticContentService>(); // all static content items Func <int, int, IEnumerable <SortInfo>, IPagedList <ContentItem> > factory = (pageNumber, pageSize, sorInfos) => { //TODO: performance and DDD specification instead if statements var contentItems = staticContentService.LoadStoreStaticContent(store).Where(x => x.Language.IsInvariant || x.Language == language); return(new StaticPagedList <ContentItem>(contentItems, pageNumber, pageSize, contentItems.Count())); }; return(builder.WithPagesAsync(() => new MutablePagedList <ContentItem>(factory, 1, 20))); }
public static Task WithDefaultShoppingCartAsync(this IWorkContextBuilder builder, Func <Model.Cart.ShoppingCart> factory) { builder.WorkContext.CurrentCart = new Lazy <Model.Cart.ShoppingCart>(factory); return(Task.CompletedTask); }
public static Task WithCatalogsAsync(this IWorkContextBuilder builder) { var serviceProvider = builder.HttpContext.RequestServices; var catalogService = serviceProvider.GetRequiredService <ICatalogService>(); //Initialize catalog search criteria builder.WorkContext.CurrentProductSearchCriteria = new ProductSearchCriteria(builder.WorkContext.CurrentLanguage, builder.WorkContext.CurrentCurrency, builder.WorkContext.QueryString); //Initialize product response group. //TODO: Need to find possibility to set this response group in theme builder.WorkContext.CurrentProductResponseGroup = EnumUtility.SafeParse(builder.WorkContext.QueryString.Get("resp_group"), ItemResponseGroup.ItemMedium | ItemResponseGroup.ItemWithPrices | ItemResponseGroup.ItemWithVendor); //This line make delay categories loading initialization (categories can be evaluated on view rendering time) builder.WorkContext.Categories = new MutablePagedList <Category>((pageNumber, pageSize, sortInfos) => { var criteria = new CategorySearchCriteria(builder.WorkContext.CurrentLanguage) { PageNumber = pageNumber, PageSize = pageSize, ResponseGroup = CategoryResponseGroup.Small }; if (string.IsNullOrEmpty(criteria.SortBy) && !sortInfos.IsNullOrEmpty()) { criteria.SortBy = SortInfo.ToString(sortInfos); } var result = catalogService.SearchCategories(criteria); foreach (var category in result) { category.Products = new MutablePagedList <Product>((pageNumber2, pageSize2, sortInfos2) => { var productSearchCriteria = new ProductSearchCriteria(builder.WorkContext.CurrentLanguage, builder.WorkContext.CurrentCurrency) { PageNumber = pageNumber2, PageSize = pageSize2, Outline = category.Outline, ResponseGroup = builder.WorkContext.CurrentProductSearchCriteria.ResponseGroup }; //criteria.CategoryId = category.Id; if (string.IsNullOrEmpty(criteria.SortBy) && !sortInfos2.IsNullOrEmpty()) { productSearchCriteria.SortBy = SortInfo.ToString(sortInfos2); } var searchResult = catalogService.SearchProducts(productSearchCriteria); //Because catalog search products returns also aggregations we can use it to populate workContext using C# closure //now workContext.Aggregation will be contains preloaded aggregations for current category builder.WorkContext.Aggregations = new MutablePagedList <Aggregation>(searchResult.Aggregations); return(searchResult.Products); }, 1, ProductSearchCriteria.DefaultPageSize); } return(result); }, 1, CategorySearchCriteria.DefaultPageSize); //This line make delay products loading initialization (products can be evaluated on view rendering time) builder.WorkContext.Products = new MutablePagedList <Product>((pageNumber, pageSize, sortInfos) => { var criteria = builder.WorkContext.CurrentProductSearchCriteria.Clone(); criteria.PageNumber = pageNumber; criteria.PageSize = pageSize; if (string.IsNullOrEmpty(criteria.SortBy) && !sortInfos.IsNullOrEmpty()) { criteria.SortBy = SortInfo.ToString(sortInfos); } var result = catalogService.SearchProducts(criteria); //Prevent double api request for get aggregations //Because catalog search products returns also aggregations we can use it to populate workContext using C# closure //now workContext.Aggregation will be contains preloaded aggregations for current search criteria builder.WorkContext.Aggregations = new MutablePagedList <Aggregation>(result.Aggregations); return(result.Products); }, 1, ProductSearchCriteria.DefaultPageSize); //This line make delay aggregation loading initialization (aggregation can be evaluated on view rendering time) builder.WorkContext.Aggregations = new MutablePagedList <Aggregation>((pageNumber, pageSize, sortInfos) => { var criteria = builder.WorkContext.CurrentProductSearchCriteria.Clone(); criteria.PageNumber = pageNumber; criteria.PageSize = pageSize; if (string.IsNullOrEmpty(criteria.SortBy) && !sortInfos.IsNullOrEmpty()) { criteria.SortBy = SortInfo.ToString(sortInfos); } //Force to load products and its also populate workContext.Aggregations by preloaded values builder.WorkContext.Products.Slice(pageNumber, pageSize, sortInfos); return(builder.WorkContext.Aggregations); }, 1, ProductSearchCriteria.DefaultPageSize); return(Task.CompletedTask); }