Pagination
Cursor-based (Images): Uses NextCursor strings
Page-index (Models, Tags, Creators): Uses WithPageIndex(n)
Page size limits: Models (1-100), Images (1-200), Tags (1-200), Creators (1-200)
Pagination Metadata
var metadataResult = await apiClient.Models
.WhereType(ModelType.Lora)
.ExecuteAsync(resultsLimit: 10);
if (metadataResult is Result<PagedResult<Model>>.Success metadataSuccess)
{
var metadata = metadataSuccess.Data.Metadata;
if (metadata is not null)
{
Console.WriteLine($"Page {metadata.CurrentPage} of {metadata.TotalPages}");
Console.WriteLine($"Total Items: {metadata.TotalItems}");
}
}
Set Page Size
// Set the number of results per page
var result = await apiClient.Models
.WhereType(ModelType.Lora)
.ExecuteAsync(resultsLimit: 25);
if (result is Result<PagedResult<Model>>.Success success)
{
Console.WriteLine($"Got {success.Data.Items.Count} items");
// Check pagination metadata
if (success.Data.Metadata is { } metadata)
{
Console.WriteLine($"Total items: {metadata.TotalItems}");
Console.WriteLine($"Total pages: {metadata.TotalPages}");
Console.WriteLine($"Has next page: {!string.IsNullOrEmpty(metadata.NextCursor)}");
}
}
Cursor Pagination
// Iterate through all pages using cursor-based pagination
var allModels = new List<Model>();
string? cursor = null;
const int pageSize = 20;
do
{
var pageResult = await apiClient.Models
.WhereType(ModelType.Lora)
.WhereTag("anime")
.ExecuteAsync(resultsLimit: pageSize, cursor: cursor);
if (pageResult is Result<PagedResult<Model>>.Success pageSuccess)
{
allModels.AddRange(pageSuccess.Data.Items);
cursor = pageSuccess.Data.Metadata?.NextCursor;
Console.WriteLine($"Fetched page with {pageSuccess.Data.Items.Count} items. " +
$"Total so far: {allModels.Count}");
// Stop after collecting 100 items for this example
if (allModels.Count >= 100)
{
break;
}
}
else
{
Console.WriteLine("Error fetching page, stopping pagination.");
break;
}
}
while (!string.IsNullOrEmpty(cursor));
Console.WriteLine($"Collected {allModels.Count} models total.");
Page Index
// For models, tags, and creators, you can use page index-based pagination
var firstPageResult = await apiClient.Models
.WhereType(ModelType.Lora)
.WithPageIndex(1)
.ExecuteAsync(resultsLimit: 20);
if (firstPageResult is Result<PagedResult<Model>>.Success firstSuccess)
{
Console.WriteLine($"Page 1: {firstSuccess.Data.Items.Count} models");
// Fetch page 2
var secondPageResult = await apiClient.Models
.WhereType(ModelType.Lora)
.WithPageIndex(2)
.ExecuteAsync(resultsLimit: 20);
if (secondPageResult is Result<PagedResult<Model>>.Success secondSuccess)
{
Console.WriteLine($"Page 2: {secondSuccess.Data.Items.Count} models");
}
}
Async Enumeration (Optional Pattern)
// Extension method example for async enumeration
public static class PaginationExtensions
{
public static async IAsyncEnumerable<T> AsAsyncEnumerable<T>(
this ModelBuilder builder,
int pageSize = 20,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
string? cursor = null;
do
{
var result = await builder.ExecuteAsync(pageSize, cursor, cancellationToken);
if (result is not Result<PagedResult<Model>>.Success success)
{
yield break;
}
foreach (var item in success.Data.Items)
{
yield return (T)(object)item;
}
cursor = success.Data.Metadata?.NextCursor;
}
while (!string.IsNullOrEmpty(cursor));
}
}
Not part of CivitaiSharp - implement in your codebase if needed.
First Result
var firstResult = await apiClient.Models
.WhereName("specific-model")
.FirstOrDefaultAsync();
if (firstResult is Result<Model?>.Success { Data: { } model })
{
Console.WriteLine($"Found: {model.Name}");
}
else
{
Console.WriteLine("Model not found");
}