Search documentationEsc

Specification pattern

Encapsulate filters, ordering, and projections in reusable specification classes.

Cosmos Repository ships with a specification pattern — inspired by ardalis/Specification — that lets you declare a query as a class and run it via IRepository<T>.QueryAsync(spec).

The base types live in Microsoft.Azure.CosmosRepository.Specification:

  • BaseSpecification<TItem> — abstract base; build a Query to add filters, ordering, and projections.
  • DefaultSpecification<TItem> — concrete subclass for ad-hoc inline use.
  • PageNumberPageSizeSpecification<TItem> — pre-wired for page-number paging.
  • ContinuationTokenSpecification<TItem> — pre-wired for continuation-token paging.

Simple specification

The specification below queries for all products in a category, ordered by price.

public class ProductSpecificationExamples
{
private class ProductsPriceLowestToHighestInCategory : DefaultSpecification<Product>
{
public ProductsPriceLowestToHighestInCategory(string categoryId) =>
Query
.Where(x => x.PartitionKey == categoryId)
.OrderBy(x => x.Price);
}
public async Task<IQueryResult<Product>> RunDemoAsync(IRepository<Product> repository)
{
IQueryResult<Product> orderedProducts = await repository
.QueryAsync(new ProductsPriceLowestToHighestInCategory("Clothing"));
return orderedProducts;
}
}

Multiple ordering clauses

Stack OrderBy / OrderByDescending with ThenBy / ThenByDescending to sort by additional properties:

public class ProductSpecificationAdvancedOrderingExamples
{
private class ProductsPriceLowestToHighestThenByName : DefaultSpecification<Product>
{
public ProductsPriceLowestToHighestThenByName() =>
Query
.OrderBy(x => x.Price)
.ThenByDescending(x => x.Name);
}
public async Task<IQueryResult<Product>> RunDemoAsync(IRepository<Product> repository)
{
IQueryResult<Product> orderedProducts = await repository
.QueryAsync(new ProductsPriceLowestToHighestThenByName());
return orderedProducts;
}
}

Built-in paging specifications

  • PageNumberPageSizeSpecification<TItem> accepts pageNumber, pageSize, and an optional returnTotal flag for total counts.
  • ContinuationTokenSpecification<TItem> accepts pageSize and a continuationToken for stable, cost-effective scrolling.

Subclass either when your specification needs paging out of the box.

Where to look in the codebase

Real specifications used in the project’s tests and the Specification sample are great references:

  • BaseSpecification<TItem> — see what Query exposes.
  • DefaultSpecification<TItem> — minimal concrete subclass.
  • IQueryResult<TItem> / IPageQueryResult<TItem> — what’s returned.