Skip to main content

Schema Validation

IEventSchemaValidator validates a CloudEvent instance against an IEventSchema and reports constraint violations as an asynchronous stream of ValidationResult objects.

Prerequisites

The validator is provided by the Hermodr.Schema package:

dotnet add package Hermodr.Schema

Interface

public interface IEventSchemaValidator
{
IAsyncEnumerable<ValidationResult> ValidateEventAsync(
IEventSchema schema,
CloudEvent @event,
CancellationToken cancellationToken = default);
}

Registration

IEventSchemaFactory and EventSchemaFactory are not automatically wired by the publisher builder. Register them explicitly:

using Hermodr;
using Microsoft.Extensions.DependencyInjection;

builder.Services.AddSingleton<IEventSchemaFactory, EventSchemaFactory>();

Note: IEventSchemaValidator defines the validation contract but its default implementation must be supplied by the application, or you can call the static EventSchema.FromDataType<T>() helpers and perform validation inline without a direct DI dependency.

Validating before publishing

using CloudNative.CloudEvents;
using Hermodr;
using System.ComponentModel.DataAnnotations;

public class OrderService
{
private readonly IEventSchemaValidator _validator;
private readonly EventPublisher _publisher;

public OrderService(IEventSchemaValidator validator, EventPublisher publisher)
{
_validator = validator;
_publisher = publisher;
}

public async Task PlaceOrderAsync(OrderPlacedData data, CancellationToken ct = default)
{
var schema = EventSchema.FromDataType<OrderPlacedData>();

var @event = new CloudEvent
{
Type = "order.placed",
Source = new Uri("https://myapp.example.com/orders"),
Data = data
};

// Collect all validation errors before publishing
var errors = new List<ValidationResult>();
await foreach (var result in _validator.ValidateEventAsync(schema, @event, ct))
{
errors.Add(result);
}

if (errors.Count > 0)
{
var messages = string.Join("; ", errors.Select(e => e.ErrorMessage));
throw new InvalidOperationException($"Event is invalid: {messages}");
}

await _publisher.PublishAsync(data, ct);
}
}

Validated constraints

The validator checks the following constraints declared in the schema against the event's data payload:

ConstraintChecked when
RequiredThe property is missing or null in the payload
Nullable: falseThe property is explicitly null
Range<T>(min, max)The value falls outside the range
Enum(values)The value is not in the allowed set

Streaming results

ValidateEventAsync returns IAsyncEnumerable<ValidationResult>, so you can process errors lazily or stop early on the first error:

// Stop on first violation
await foreach (var result in _validator.ValidateEventAsync(schema, @event))
{
throw new InvalidOperationException(result.ErrorMessage);
}