Skip to content

SaaS domain implementation patterns

Wave-2 conventions shared by all five ConnectSoft.Saas.<Context>Template repositories. Entitlements is the reference for acceptance depth and gap traceability; Products Catalog is the reference for gRPC API documentation depth.

Repo Metrics class Validators Metrics unit tests
Tenants TenantsMetrics 8 5
Products Catalog ProductsCatalogMetrics 9 6
Entitlements EntitlementsMetrics 7 11
Billing BillingMetrics 7 6
Metering MeteringMetrics 8 6

Each template documents its concrete validator list and instrument names in docs/domain-implementation.md.

FluentValidation

  • Validators live in src/ConnectSoft.Saas.<Context>.DomainModel.Impl/Validators/.
  • One public validator class per file with Entitlements-style XML documentation.
  • Default*Processor and Default*Retriever inject IValidator<TInput> and call ValidateAndThrowAsync before domain work.
  • Registration: AddConnectSoftFluentValidation<MarkerValidator> assembly scan in <Context>MicroserviceRegistration.
  • Unit tests: one *ValidatorUnitTests.cs per validator under tests/.../DomainModel/Validators/.
dotnet test tests/ConnectSoft.Saas.<Context>.UnitTests/ConnectSoft.Saas.<Context>.UnitTests.csproj --filter "FullyQualifiedName~Validator"

Validation failures surface as REST problem details and, on gRPC, as ValidationFault (FaultContract strategy) or rich BadRequest details (RichError strategy).

Domain metrics

  • <Context>Metrics in src/ConnectSoft.Saas.<Context>.Metrics/.
  • OpenTelemetry meter name: ConnectSoft.Saas.<Context> (see *MetricsMeterName constant).
  • Instrument naming: {meter}.{operation}.{succeeded|failed} counters and {meter}.{operation}.duration histograms (seconds).
  • Registration: RegisterTemplateMetrics registers the metrics singleton in <Context>MicroserviceRegistration.
  • Default*Processor and Default*Retriever record success in the try path and failure in catch blocks (never alias unrelated instruments).

Unit tests use MetricCollector and Microsoft.Extensions.Diagnostics.Testing (see ConnectSoft.IdentityTemplate metrics tests for additional examples):

dotnet test tests/ConnectSoft.Saas.<Context>.UnitTests/ConnectSoft.Saas.<Context>.UnitTests.csproj --filter "FullyQualifiedName~Metrics"

Run across all five repos: 34 metrics tests (wave 2).

Note

SaaS templates use RegisterTemplateMetrics and dedicated *Metrics classes. The generic IMetricsFeature extension pattern in Metrics, Options and Testing Extensibility still applies to other templates (Identity, BaseTemplate features).

Processor and retriever logging

Follow DefaultEntitlementsProcessor:

  1. using (logger.BeginScopeWithFlow(...)) with tenant/aggregate correlation properties.
  2. logger.Here().LogInformation(...) at operation start.
  3. try / catch: error log + metrics failure recorder in catch; success log + metrics success recorder after commit.
  4. Avoid logging before validation — validate first, then enter the scoped operation log.

gRPC rich errors

Each SaaS repo owns GrpcRichErrorInterceptor in src/ConnectSoft.Saas.<Context>.ApplicationModel/ (not the generic base-template copy). GrpcExtensions registers it when:

"Grpc": {
  "GrpcErrorHandlingStrategy": "RichError"
}

Supported values: FaultContract (ServiceModel.Grpc fault DTOs) and RichError (Google Rpc.Status with ErrorInfo, validation field violations, NHibernate mapping). See gRPC communication architecture for the platform-wide comparison.

XML documentation

ConnectSoft.Saas.<Context>.DomainModel, ServiceModel, and validator classes carry multi-line XML summaries. Interfaces document param and returns. Regenerated scaffolding from <Context>.json must be upgraded to this standard when touched.