This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is a Xperience by Kentico middleware library that provides image processing capabilities for the Xperience by Kentico platform. It's packaged as a NuGet package for distribution.
Note: Kentico now offers native Image Variants (https://docs.kentico.com/documentation/business-users/content-hub/content-item-assets#image-variants) for Content Hub assets. This package remains useful for Media library support, on-the-fly processing, and dynamic transformations. Future deprecation is planned as Kentico's native solution matures.
Key Technology Stack:
- Backend: .NET 8.0, ASP.NET Core, Xperience by Kentico 30.11.1+
- Image Processing: SkiaSharp 3.119.1
- Supported formats: WebP, JPEG, PNG
This project provides an ASP.NET Core middleware that intercepts image requests and performs on-the-fly processing:
-
Middleware Registration (
src/Middleware/ImageProcessingMiddleware.cs)UseXperienceCommunityImageProcessing()extension method registers the middleware- Intercepts requests to
/getmedia/*(Media library) and/getContentAsset/*(Content hub assets)
-
Image Processing
- Query parameters:
width,height,maxSideSize,format,fit,crop - Supports format conversion:
webp,jpg,png - Supports fit modes:
contain(default),cover,fill - Supports crop positioning:
center(default),north,south,east,west,northeast,northwest,southeast,southwest - Uses SkiaSharp for high-quality image resizing
- ETags for client-side caching
- Query parameters:
-
Configuration Options (
ImageProcessingOptions)ProcessMediaLibrary: Enable/disable processing for Media library images (default: true)ProcessContentItemAssets: Enable/disable processing for Content hub assets (default: true)MaxWidth: Maximum allowed width in pixels, requests exceeding this are capped (default: 5000)MaxHeight: Maximum allowed height in pixels, requests exceeding this are capped (default: 5000)MaxSideSize: Maximum allowed maxSideSize parameter, requests exceeding this are capped (default: 5000)Quality: JPEG/WebP encoding quality 1-100, higher is better quality but larger file size (default: 80)
The middleware supports optional configuration via ASP.NET Core configuration:
{
"ImageProcessing": {
"ProcessMediaLibrary": true,
"ProcessContentItemAssets": true,
"MaxWidth": 5000,
"MaxHeight": 5000,
"MaxSideSize": 5000,
"Quality": 80
}
}Registered in the consuming app via:
// Optional: Configure which paths to process
builder.Services.Configure<ImageProcessingOptions>(builder.Configuration.GetSection("ImageProcessing"));
var app = builder.Build();
// Required: Register Kentico first
app.UseKentico();
// Then register image processing middleware
app.UseXperienceCommunityImageProcessing();dotnet restore
dotnet build --configuration ReleaseThe NuGet package is auto-generated in src/bin/Release/ due to <GeneratePackageOnBuild>true</GeneratePackageOnBuild>.
There are no automated tests in this project currently. The examples/DancingGoat project serves as an integration test environment.
This project uses Central Package Management via Directory.Packages.props:
- All NuGet package versions are centralized in
Directory.Packages.props - Individual
.csprojfiles reference packages WITHOUT version attributes packages.lock.jsonis generated and committed for reproducible builds- Kentico packages are currently at 30.11.1
Important: When updating Kentico packages, update all three together:
Kentico.Xperience.webappKentico.Xperience.adminKentico.Xperience.azurestorage
- Middleware intercepts image requests to
/getmedia/*or/getContentAsset/* - Original image is fetched by calling next middleware in pipeline
- Response is captured in a memory stream
- If resize/format query parameters are present, image is processed
- ETag is generated from original image bytes + parameters
- If client's If-None-Match matches ETag, return 304 Not Modified
- Otherwise, process image with SkiaSharp and return modified response
- Cache-Control header set to 1 year for processed images
- Uses SkiaSharp for high-performance image manipulation
SKSamplingOptionswith linear filtering for best resize quality- Configurable quality setting (default: 80) for JPEG/WebP encoding
- Maintains aspect ratio when only width or height specified
maxSideSizeparameter scales largest dimension to specified size- Automatic parameter validation: dimensions exceeding configured maximums are clamped
- Proper resource disposal with try-finally pattern for bitmap memory management
- contain (default): Fit image inside dimensions, maintaining aspect ratio (letterbox if needed)
- cover: Fill dimensions exactly, cropping excess while maintaining aspect ratio
- fill: Stretch image to exact dimensions, ignoring aspect ratio
When using fit=cover, the crop parameter controls where to crop from:
- center (default): Crop from center
- north: Crop from top center
- south: Crop from bottom center
- east: Crop from middle right
- west: Crop from middle left
- northeast, northwest, southeast, southwest: Corner positions
- ETags generated from MD5 hash of: original image bytes + width + height + maxSideSize + format + fitMode + cropPosition
- Clients can use If-None-Match header for cache validation
- Cache-Control: public, max-age=31536000 (1 year)
- Content-Disposition: inline with proper filename and extension
- Different fit/crop combinations generate unique ETags for proper cache differentiation
GitHub Actions workflows:
- CI (
.github/workflows/ci.yml): Runs on PRs to main, builds and tests - Publish (
.github/workflows/publish.yml): Publishes to NuGet.org on GitHub releases using OIDC trusted publishing
Dependabot (.github/dependabot.yml):
- Weekly updates for NuGet packages (ignores Kentico.Xperience.*)
- Weekly updates for GitHub Actions
The examples/DancingGoat directory contains a sample Xperience by Kentico website that demonstrates the middleware integration. This serves as both documentation and a manual testing environment.
- Middleware order matters: Must be called AFTER
app.UseKentico()so Kentico can serve the original images - SkiaSharp native dependencies: The package includes
SkiaSharp.NativeAssets.Linux.NoDependenciesfor Linux deployments - Memory usage: Large images are loaded into memory for processing - monitor memory usage in high-traffic scenarios
- ETag caching: ETags are based on original image content, so clearing CDN/browser cache may be needed when images are updated
- Parameter clamping: Dimension values exceeding configured maximums (MaxWidth, MaxHeight, MaxSideSize) are automatically capped, not rejected
- Quality clamping: Quality values outside 1-100 range are clamped to valid range