Pular para o conteúdo principal
Versão: main (dev) 🚧

ITLab.Template.DevPack.Guards

Custom Ardalis guard clause extensions for object equality, DateTimeOffset/TimeSpan comparisons, and DateOnly invariants.

Histórico: estas classes viviam em Extensions/GuardExtensions.cs (arquivo único com três classes coabitando) até a versão 2.0.1. Movidas para a área dedicada Guards/ em 2.0.2 — namespace ITLab.Template.DevPack.Guards. Veja CHANGELOG.md para a nota de migração.

Componentes

TipoNomeResponsabilidade
Static ClassObjectGuardsGeneric equality guards: Equal<T>, NotEqual<T>
Static ClassDateTimeOffsetGuardsComparison guards for DateTimeOffset and TimeSpan (LessThan, LessThanOrEqualTo, Greater/GreaterThan, GreaterThanOrEqualTo) and MustBeQuarterHourRounded
Static ClassDateOnlyGuardsDate invariants: NotFirstDayOfMonth, NotLastDayOfMonth
Static ClassDocumentGuardsBrazilian fiscal documents: InvalidCpf, InvalidCnpj (returns normalized digits-only on success)

Como usar

using Ardalis.GuardClauses;
using ITLab.Template.DevPack.Guards;

// Object equality
Guard.Against.NotEqual(actualStatus, expectedStatus, nameof(actualStatus));
Guard.Against.Equal(value, forbiddenValue, nameof(value));

// DateTimeOffset / TimeSpan comparison
Guard.Against.LessThan(end, start, nameof(end)); // throws if end < start
Guard.Against.GreaterThanOrEqualTo(timeout, maxAllowed, nameof(timeout));

// Quarter-hour-rounded scheduling
var slot = Guard.Against.MustBeQuarterHourRounded(scheduledAt, nameof(scheduledAt));

// DateOnly invariants
Guard.Against.NotFirstDayOfMonth(billingCycleStart, nameof(billingCycleStart));

// Brazilian fiscal documents — guard returns the normalized digits-only value.
public Cpf(string raw)
{
Value = Guard.Against.InvalidCpf(raw, nameof(raw)); // throws ArgumentException if invalid
}

O que não fazer

  • Do not throw ArgumentException directly when one of these guards covers the case — use the guard for consistent messages.
  • Do not catch ArgumentException from guards inside handlers; let it propagate to the pipeline boundary so the global exception handler maps it to a 400 Bad Request.
  • Do not register Guard.Against extensions globally in DI — they are static methods on IGuardClause.

Extensão pelo produto

  • Products can add product-specific guards in their own namespace (e.g. MyApp.Guards) by declaring static extension classes on IGuardClause. Keep one class per concept.
  • The DevPack does not impose a discoverability mechanism beyond the using ITLab.Template.DevPack.Guards; directive — consumers add the using only where they need the extensions.