Skip to content
Merged
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
27 changes: 23 additions & 4 deletions .ai/knowledge/async.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,35 @@ var result = await _repository.GetByIdAsync(id);

`ValueTask` avoids allocation for code that often returns a cached result without awaiting. Do not retrofit existing `Task`-returning code unless profiling shows allocation is a problem.

### Avoid `.ToList()` inside async lambdas passed to cache
### Never execute a query built on `Table` synchronously

`IQueryable<T>.ToList()` is synchronous and blocks. Use LINQ's `ToList()` only on in-memory sequences, or use repository methods that return `Task<IList<T>>`.
`Table` is an `IQueryable` over the MongoDB driver. `ToList()`, `Count()`, `First()` and plain
enumeration on it each issue a **blocking** round trip and hold a thread pool thread for its
duration. Being MongoDB rather than EF does not make it synchronous-safe — it makes it a network
call with no async on that path unless you ask for one.

Execute through the repository instead. `MongoRepository` runs the query on the driver's
asynchronous API. Hand it a sequence you already materialised and it throws — that is deliberate,
because quietly enumerating it would be the very pattern this rule exists to remove.

```csharp
// This is fine — the LINQ query is materialised synchronously here
// because Table is IQueryable against MongoDB, not EF
// wrong — blocks a thread for the whole round trip
var productIds = query.Take(request.ProductsNumber).ToList();
var total = query.Count();
return new PagedList<Product>(query, pageIndex, pageSize);

// correct
var productIds = await _productRepository.ToListAsync(query.Take(request.ProductsNumber));
var total = await _productRepository.CountAsync(query);
return await _productRepository.PagedAsync(query, pageIndex, pageSize);
```

The same applies inside a lambda passed to `ICacheBase.GetAsync` — make the lambda `async` and
await the repository, rather than returning `Task.FromResult(query.ToList())`. Blocking there is
worse than elsewhere, because the cache holds a lock while the acquire function runs.

`ToList()` on a sequence that is already in memory is fine and needs no repository call.

### Run independent operations concurrently with `Task.WhenAll`

When two or more async operations are independent, start all of them before awaiting:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@ public async Task<IPagedList<DiscountUsageHistory>> Handle(GetDiscountUsageHisto
query = query.Where(duh => duh.Canceled == request.Canceled.Value);
query = query.OrderByDescending(c => c.CreatedOnUtc);

return await PagedList<DiscountUsageHistory>.Create(query, request.PageIndex, request.PageSize);
return await _discountUsageHistoryRepository.PagedAsync(query, request.PageIndex, request.PageSize);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public GetSearchProductsQueryHandler(
query = OrderByQueryable(request, query);

// Create paged list
var products = await PagedList<Product>.Create(query, request.PageIndex, request.PageSize);
var products = await _productRepository.PagedAsync(query, request.PageIndex, request.PageSize);

// Get filterable specification attributes if needed
if (ShouldLoadFilterableSpecifications(request))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public virtual async Task<IPagedList<Brand>> GetAllBrands(string brandName,
}

query = query.OrderBy(m => m.DisplayOrder).ThenBy(m => m.Name);
return await PagedList<Brand>.Create(query, pageIndex, pageSize);
return await _brandRepository.PagedAsync(query, pageIndex, pageSize);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public virtual async Task<IPagedList<Category>> GetAllCategories(string parentId
query = query.OrderBy(c => c.DisplayOrder).ThenBy(c => c.Name);

//pagination
return await Task.FromResult(new PagedList<Category>(query, pageIndex, pageSize));
return await _categoryRepository.PagedAsync(query, pageIndex, pageSize);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public virtual async Task<IPagedList<ProductsCategory>> GetProductCategoriesByCa
var key = string.Format(CacheKey.PRODUCTCATEGORIES_ALLBYCATEGORYID_KEY, showHidden, categoryId, pageIndex,
pageSize, string.Join(",", _contextAccessor.WorkContext.CurrentCustomer.GetCustomerGroupIds()),
_contextAccessor.StoreContext.CurrentStore.Id);
return await _cacheBase.GetAsync(key, () =>
return await _cacheBase.GetAsync(key, async () =>
{
var query = _productRepository.Table.Where(x => x.ProductCategories.Any(y => y.CategoryId == categoryId));

Expand Down Expand Up @@ -91,7 +91,7 @@ from pc in prod.ProductCategories
orderby pm.DisplayOrder
select pm;

return Task.FromResult(new PagedList<ProductsCategory>(queryProductCategories, pageIndex, pageSize));
return await _productRepository.PagedAsync(queryProductCategories, pageIndex, pageSize);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public virtual async Task<IPagedList<Collection>> GetAllCollections(string colle
}

query = query.OrderBy(m => m.DisplayOrder).ThenBy(m => m.Name);
return await PagedList<Collection>.Create(query, pageIndex, pageSize);
return await _collectionRepository.PagedAsync(query, pageIndex, pageSize);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public virtual async Task<IPagedList<ProductsCollection>> GetProductCollectionsB
{
var key = string.Format(CacheKey.PRODUCTCOLLECTIONS_ALLBYCOLLECTIONID_KEY, showHidden, collectionId, pageIndex,
pageSize, string.Join(",", _contextAccessor.WorkContext.CurrentCustomer.GetCustomerGroupIds()), storeId);
return await _cacheBase.GetAsync(key, () =>
return await _cacheBase.GetAsync(key, async () =>
{
var query = _productRepository.Table.Where(x =>
x.ProductCollections.Any(y => y.CollectionId == collectionId));
Expand Down Expand Up @@ -84,7 +84,7 @@ from pm in prod.ProductCollections
orderby pm.DisplayOrder
select pm;

return Task.FromResult(new PagedList<ProductsCollection>(queryProductCollection, pageIndex, pageSize));
return await _productRepository.PagedAsync(queryProductCollection, pageIndex, pageSize);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ into groupedResult
Keyword = r.Keyword,
Count = r.Count
});
return await PagedList<SearchTermReportLine>.Create(query, pageIndex, pageSize);
return await _searchTermRepository.PagedAsync(query, pageIndex, pageSize);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ public virtual async Task<IPagedList<DiscountCoupon>> GetAllCouponCodesByDiscoun
query = query.Where(duh => duh.DiscountId == discountId);
query = query.OrderByDescending(c => c.CouponCode);

return await PagedList<DiscountCoupon>.Create(query, pageIndex, pageSize);
return await _discountCouponRepository.PagedAsync(query, pageIndex, pageSize);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@ public virtual async Task<IPagedList<Bid>> GetBidsByProductId(string productId,
int pageSize = int.MaxValue)
{
var query = _bidRepository.Table.Where(x => x.ProductId == productId).OrderByDescending(x => x.Date);
return await Task.FromResult(new PagedList<Bid>(query, pageIndex, pageSize));
return await _bidRepository.PagedAsync(query, pageIndex, pageSize);
}

public virtual async Task<IPagedList<Bid>> GetBidsByCustomerId(string customerId, int pageIndex = 0,
int pageSize = int.MaxValue)
{
var query = _bidRepository.Table.Where(x => x.CustomerId == customerId);
return await Task.FromResult(new PagedList<Bid>(query, pageIndex, pageSize));
return await _bidRepository.PagedAsync(query, pageIndex, pageSize);
}

public virtual async Task InsertBid(Bid bid)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public virtual async Task<IPagedList<OutOfStockSubscription>> GetAllSubscription

query = query.OrderByDescending(x => x.CreatedOnUtc);

return await PagedList<OutOfStockSubscription>.Create(query, pageIndex, pageSize);
return await _outOfStockSubscriptionRepository.PagedAsync(query, pageIndex, pageSize);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public virtual async Task<IPagedList<ProductAttribute>> GetAllProductAttributes(
int pageSize = int.MaxValue)
{
var key = string.Format(CacheKey.PRODUCTATTRIBUTES_ALL_KEY, storeId, pageIndex, pageSize);
return await _cacheBase.GetAsync(key, () =>
return await _cacheBase.GetAsync(key, async () =>
{
var query = from pa in _productAttributeRepository.Table
select pa;
Expand All @@ -74,7 +74,7 @@ public virtual async Task<IPagedList<ProductAttribute>> GetAllProductAttributes(

query = query.OrderBy(pa => pa.Name);

return Task.FromResult(new PagedList<ProductAttribute>(query, pageIndex, pageSize));
return await _productAttributeRepository.PagedAsync(query, pageIndex, pageSize);
});


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public virtual async Task<IPagedList<ProductReservation>> GetProductReservations
}

query = query.OrderBy(x => x.Date);
return await PagedList<ProductReservation>.Create(query, pageIndex, pageSize);
return await _productReservationRepository.PagedAsync(query, pageIndex, pageSize);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public virtual async Task<IPagedList<ProductReview>> GetAllProductReviews(string

query = query.OrderByDescending(c => c.CreatedOnUtc);

return await PagedList<ProductReview>.Create(query, pageIndex, pageSize);
return await _productReviewRepository.PagedAsync(query, pageIndex, pageSize);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ public virtual async Task<IPagedList<Product>> GetProductsByDiscount(string disc
where c.AppliedDiscounts.Any(x => x == discountId)
select c;

return await PagedList<Product>.Create(query, pageIndex, pageSize);
return await _productRepository.PagedAsync(query, pageIndex, pageSize);
}


Expand Down Expand Up @@ -577,7 +577,7 @@ public virtual async Task<IPagedList<Product>> GetProductsByProductAttributeId(s

query = query.OrderBy(x => x.Name);

return await PagedList<Product>.Create(query, pageIndex, pageSize);
return await _productRepository.PagedAsync(query, pageIndex, pageSize);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public virtual async Task<IPagedList<SpecificationAttribute>> GetSpecificationAt

query = query.OrderBy(sa => sa.DisplayOrder).ThenBy(sa => sa.Name);

return await PagedList<SpecificationAttribute>.Create(query, pageIndex, pageSize);
return await _specificationAttributeRepository.PagedAsync(query, pageIndex, pageSize);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public virtual async Task<IPagedList<GiftVoucher>> GetAllGiftVouchers(string pur
};

var query = await _mediator.Send(model);
return await PagedList<GiftVoucher>.Create(query, pageIndex, pageSize);
return await _giftVoucherRepository.PagedAsync(query, pageIndex, pageSize);
}

public virtual async Task<IList<GiftVoucherUsageHistory>> GetAllGiftVoucherUsageHistory(string orderId = "")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public virtual async Task<IPagedList<MerchandiseReturn>> SearchMerchandiseReturn
};

var query = await _mediator.Send(model);
return await PagedList<MerchandiseReturn>.Create(query, pageIndex, pageSize);
return await _merchandiseReturnRepository.PagedAsync(query, pageIndex, pageSize);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ orderby p.Name
(showHidden || p.Published)
select p;

return await PagedList<Product>.Create(qproducts, pageIndex, pageSize);
return await _productRepository.PagedAsync(qproducts, pageIndex, pageSize);
}

public class OrderStats
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ public virtual async Task<IPagedList<Order>> SearchOrders(string storeId = "",
SalesEmployeeId = salesEmployeeId
};
var query = await _mediator.Send(queryModel);
return await PagedList<Order>.Create(query, pageIndex, pageSize);
return await _orderRepository.PagedAsync(query, pageIndex, pageSize);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ public virtual async Task<IPagedList<PaymentTransaction>> SearchPaymentTransacti
};

var query = await _mediator.Send(model);
return await PagedList<PaymentTransaction>.Create(query, pageIndex, pageSize);
return await _repositoryPaymentTransaction.PagedAsync(query, pageIndex, pageSize);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public virtual async Task<IPagedList<DeliveryDate>> GetAllDeliveryDates(string s
query = query.Where(dd => dd.StoreId == storeId);
query = query.OrderBy(dd => dd.DisplayOrder);

return await PagedList<DeliveryDate>.Create(query, pageIndex, pageSize);
return await _deliveryDateRepository.PagedAsync(query, pageIndex, pageSize);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public virtual async Task<IPagedList<PickupPoint>> GetAllPickupPoints(string sto
query = query.Where(pp => pp.StoreId == storeId);

query = query.OrderBy(pp => pp.DisplayOrder);
return await PagedList<PickupPoint>.Create(query, pageIndex, pageSize);
return await _pickupPointsRepository.PagedAsync(query, pageIndex, pageSize);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public virtual async Task<IPagedList<Shipment>> GetAllShipments(string storeId =
query = query.Where(s => createdToUtc.Value >= s.CreatedOnUtc);

query = query.OrderByDescending(x => x.CreatedOnUtc);
var shipments = await PagedList<Shipment>.Create(query, pageIndex, pageSize);
var shipments = await _shipmentRepository.PagedAsync(query, pageIndex, pageSize);
return shipments;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public virtual async Task<IPagedList<Warehouse>> GetAllWarehouses(string storeId
query = query.Where(wh => wh.StoreId == storeId);
query = query.OrderBy(wh => wh.DisplayOrder);

return await PagedList<Warehouse>.Create(query, pageIndex, pageSize);
return await _warehouseRepository.PagedAsync(query, pageIndex, pageSize);
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion src/Business/Grand.Business.Cms/Services/BlogService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public virtual async Task<IPagedList<BlogPost>> GetAllBlogPosts(string storeId =

query = query.OrderByDescending(b => b.CreatedOnUtc);

return await PagedList<BlogPost>.Create(query, pageIndex, pageSize);
return await _blogPostRepository.PagedAsync(query, pageIndex, pageSize);
}


Expand Down
2 changes: 1 addition & 1 deletion src/Business/Grand.Business.Cms/Services/NewsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public virtual async Task<IPagedList<NewsItem>> GetAllNews(string storeId = "",
}

query = query.OrderByDescending(n => n.CreatedOnUtc);
return await PagedList<NewsItem>.Create(query, pageIndex, pageSize);
return await _newsItemRepository.PagedAsync(query, pageIndex, pageSize);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public virtual async Task<IPagedList<CustomerGroup>> GetAllCustomerGroups(string

query = query.OrderBy(m => m.DisplayOrder).ThenBy(m => m.Name);

return await PagedList<CustomerGroup>.Create(query, pageIndex, pageSize);
return await _customerGroupRepository.PagedAsync(query, pageIndex, pageSize);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ public virtual async Task<IPagedList<EntityUrl>> GetAllEntityUrl(string slug = "
query = query.Where(ur => ur.IsActive == active.Value);

query = query.OrderBy(ur => ur.Slug);
return await PagedList<EntityUrl>.Create(query, pageIndex, pageSize);
return await _urlEntityRepository.PagedAsync(query, pageIndex, pageSize);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ Task<string> GetPictureUrl(Picture picture,
/// <param name="pageIndex">Current page</param>
/// <param name="pageSize">Items on each page</param>
/// <returns>Paged list of pictures</returns>
IPagedList<Picture> GetPictures(int pageIndex = 0, int pageSize = int.MaxValue);
Task<IPagedList<Picture>> GetPictures(int pageIndex = 0, int pageSize = int.MaxValue);

/// <summary>
/// Inserts a picture
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public interface ICustomerReportService
/// <param name="pageIndex">Page index</param>
/// <param name="pageSize">Page size</param>
/// <returns>Report</returns>
IPagedList<BestCustomerReportLine> GetBestCustomersReport(string storeId = "", string vendorId = "",
Task<IPagedList<BestCustomerReportLine>> GetBestCustomersReport(string storeId = "", string vendorId = "",
DateTime? createdFromUtc = null,
DateTime? createdToUtc = null, int? os = null, PaymentStatus? ps = null, ShippingStatus? ss = null,
int orderBy = 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public virtual async Task<IPagedList<Affiliate>> GetAllAffiliates(string friendl

query = query.OrderByDescending(a => a.Id);

return await PagedList<Affiliate>.Create(query, pageIndex, pageSize);
return await _affiliateRepository.PagedAsync(query, pageIndex, pageSize);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public CustomerReportService(IRepository<Customer> customerRepository,
/// <param name="pageIndex">Page index</param>
/// <param name="pageSize">Page size</param>
/// <returns>Report</returns>
public virtual IPagedList<BestCustomerReportLine> GetBestCustomersReport(string storeId = "", string vendorId = "",
public virtual async Task<IPagedList<BestCustomerReportLine>> GetBestCustomersReport(string storeId = "", string vendorId = "",
DateTime? createdFromUtc = null,
DateTime? createdToUtc = null, int? os = null, PaymentStatus? ps = null, ShippingStatus? ss = null,
int orderBy = 0,
Expand Down Expand Up @@ -101,7 +101,7 @@ into g
_ => throw new ArgumentException("Wrong orderBy parameter", nameof(orderBy))
};

var tmp = new PagedList<dynamic>(query2, pageIndex, pageSize);
var tmp = await _orderRepository.PagedAsync(query2, pageIndex, pageSize);
return new PagedList<BestCustomerReportLine>(tmp.Select(x => new BestCustomerReportLine {
CustomerId = x.CustomerId,
OrderTotal = x.OrderTotal,
Expand Down Expand Up @@ -135,7 +135,7 @@ into g
_ => throw new ArgumentException("Wrong orderBy parameter", nameof(orderBy))
};

var vendorReport = new PagedList<dynamic>(vendorQueryGroup, pageIndex, pageSize);
var vendorReport = await _orderRepository.PagedAsync(vendorQueryGroup, pageIndex, pageSize);
return new PagedList<BestCustomerReportLine>(vendorReport.Select(x => new BestCustomerReportLine {
CustomerId = x.CustomerId,
OrderTotal = x.OrderTotal,
Expand Down
Loading
Loading