-
Book Overview & Buying
-
Table Of Contents
-
Feedback & Rating
ASP.NET Core 9 Web API Cookbook
By :
.NET 9 introduces CountBy(), a powerful new LINQ method that simplifies the common task of grouping and counting elements. This method replaces the traditional pattern of combining GroupBy with Count, making your code more concise and readable. In this recipe, we’ll create an endpoint that uses CountBy() to efficiently report how many products exist in each category, demonstrating how this new method can simplify data aggregation tasks.
You can clone the starter project for this recipe here: https://github.com/PacktPublishing/ASP.NET-9-Web-API-Cookbook/tree/main/start/chapter01/countBy.
Models folder and create a new file called CategoryDTO.cs. In this file, we will define a new DTO record:namespace CountBy.Models;
public record CategoryDTO
{
public int CategoryId { get; init; }
public int ProductCount { get; init; }
}Services folder, create a file named IProductsService.cs. In this file, we are going to define a contract for a GetCategoryInfoAsync service method:using CountBy.Models;
namespace CountBy.Services;
public interface IProductsService {
Task<IEnumerable<ProductDTO>> GetAllProductsAsync();
Task<IReadOnlyCollection<CategoryDTO>> GetCategoryInfoAsync();
}CountBy() on your DbContext:public async Task<IReadOnlyCollection<CategoryDTO>> GetCategoryInfoAsync()
{
var products = await context.Products.AsNoTracking(). ToListAsync();
var productsByCategory = products.CountBy(p => p.CategoryId).OrderBy(x => x.Key);
return productsByCategory.Select(categoryGroup => new
CategoryDTO
{
CategoryId = categoryGroup.Key,
ProductCount = categoryGroup.Value
}).ToList(
}ProductsController.cs file in the Controllers folder. Add the attributes to the CategoryInfo endpoint:// GET: /Products/CategoryInfo
[HttpGet("CategoryInfo")]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<CategoryDTO>))]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]GetCategoryInfo controller method:public async Task<ActionResult<IEnumerable<CategoryDTO>>> GetCategoryInfo()
{
logger.LogInformation("Retrieving Category Info");
try
{
var products = await productsService. GetCategoryInfoAsync();
if (!products.Any())
return NoContent();
return Ok(products);
}
catch (Exception ex)
{
logger.LogError(ex, "An error occurred while retrieving all products");
return StatusCode(StatusCodes. Status500InternalServerError);
}
}dotnet run
Products/CategoryInfo and see how many products you have in each category.Since this is a GET endpoint, we can test it with our web browser, as shown in the following screenshot:
Figure 1.2 – Our data now with a categoryId
We explored the use of the new LINQ CountBy() operator to create an endpoint that returns how many products you have by each category. CountBy() provides a new, more elegant way to categorize data, replacing the need to use both GroupBy() and Count() in aggregation operations. It’s important to note that CountBy() is a LINQ-to-objects method, not a LINQ-to-entities method. This means when used with EF Core, it will first materialize the query (loading all records into memory) before performing the counting operation. For large datasets in production scenarios, you might want to consider using GroupBy() directly on the IQueryable instead. In addition to database queries, CountBy() is particularly useful for in-memory operations such as analyzing API usage statistics by grouping and counting requests based on different criteria such as client IP, user agent, or endpoint path.