Application operations

Registration and lookup belong to an application service, so HTTP, console and batch callers can share the same policy. This step uses the Customer model and validator; the next step supplies CustomerRepository. Keep one copy of each declaration.

Place this class in CustomerRegistrationService.ds in the same application assembly as CustomerRepository and CustomerValidator. It contains no HTTP types, so console, import and web callers can share it.

import Global.System
import Global.FluentValidation.Results

public class CustomerRegistrationService
    private readonly repository as CustomerRepository
    private readonly validator as CustomerValidator

    public constructor(storage as CustomerRepository, inputRules as CustomerValidator)
        require storage is not nothing
        require inputRules is not nothing
        repository = storage
        validator = inputRules
    end constructor

    public action Check(customer as Customer)
        returns ValidationResult
        require customer is not nothing
        return validator.Validate(customer)
    end action

    public async action RegisterAsync(customer as Customer)
        returns Guid
        require customer is not nothing
        require Check(customer).IsValid
        Cancellation.ThrowIfCanceled()
        customer.Id = Guid.NewGuid()
        customer.IsActive = false
        await repository.AddAsync(customer)
        return customer.Id
    end action

    public async action FindAsync(id as Guid)
        returns Customer
        return await repository.FindAsync(id)
    end action
end class

RegisterAsync assigns the identifier itself and starts the customer inactive. Its precondition protects non-HTTP callers as well. The controller validates before calling it so ordinary input errors produce a response, while the service independently protects its boundary. Local validation is repeated intentionally; expensive asynchronous rules would need a different orchestration policy.

Explicit async service calls propagate cancellation to the DirectSharp repository. Across the C# boundary, pass the token through the normal final cancellation parameter.

Previous: model and validation. Next: persistence.