Skip to content

ETag and If‐None‐Match

Ieuan Walker edited this page Jun 25, 2026 · 3 revisions

ETags enable conditional requests: the client can send If-None-Match and the server can respond 304 Not Modified when the representation hasn’t changed.

This is complementary to output caching:

  • Output caching can avoid re-executing endpoint handlers on the server.
  • ETags can avoid re-downloading content to the client.

Basic flow

  1. Server returns a response with an ETag header.
  2. Client caches the response and sends If-None-Match: <etag> on subsequent requests.
  3. If unchanged, server returns 304 Not Modified with no body.

Creating an ETag

An ETag should represent the current state of the resource, and should be deterministic so the same etag is generated if the data is unchanged. This is because if some clients don't use ETags then they will be hitting the api logic each time, so if the etag generation logic deterministic it wont create a new tag and invalidate cached data of clients that use Etags

Common sources:

  • Deterministic ETag based on the serialized object content
    • A convenient extension method has been created to generate an etag based on an object - GenerateEtag
  • A row-version / concurrency token
  • A last-updated timestamp

A simple example using the provided extension method:

public class GetItemEndpoint : IEndpointWithoutRequest<ItemModel>
{
	readonly IHttpContextAccessor _context;

	public GetItemEndpoint (IHttpContextAccessor context)
	{
		_context = context ?? throw new ArgumentNullException(nameof(context));
	}

	public static void Configure(RouteHandlerBuilder builder)
	{
		builder
			.Get("/items/{id:int}")
			.CacheOutput(TimeSpan.FromMinutes(5));
	}

	public async Task<ItemModel> Handle(CancellationToken ct)
	{
		ItemModel item = new { Id = 1, Name = "Example", UpdatedAt = new DateTime(1996, 06, 08) };

		_context.HttpContext?.Response.Headers.ETag = item.GenerateEtag();

		return item;
	}
}

Notes:

  • ETag values are typically quoted

Clone this wiki locally