Skip to content

Validation

Validation system is used to validate the user input or client request for a particular controller action or service method.

This section briefly introduces the validation system. For details, see the ASP.NET Core validation documentation.

  • Do use data annotations for simple formal validations
    • Do extend DTO classes from ExtensibleObject. This will be ensure DTO can be extensible in the future.

It simply defines a Dictionary property:

ExtraPropertyDictionary ExtraProperties { get; }

ExtraPropertyDictionary class is inherited from the Dictionary class. You can add or get extra properties using this dictionary.

[Serializable]
public class CreateModelInput : ExtensibleObject
{
    /// <summary>
    /// The name of the model to be created
    /// </summary>
    [Required]
    [StringLength(maximumLength: 64)]
    public string Name { get; set; }

    /// <summary>
    /// Description for the model if necessary
    /// </summary>
    [StringLength(maximumLength: 128)]
    public string Description { get; set; }

    /// <summary>
    /// The name of the server to be connected
    /// </summary>
    [Required]
    [StringLength(maximumLength: 64]
    public string ServerName { get; set; }

    /// <summary>
    /// CIM model version to be initialized
    /// </summary>
    [Required]
    public CIMVersionType CIMVersionType { get; set; } = CIMVersionType.CIM16v28;

    /// <summary>
    /// Flag to overwrite existing model
    /// </summary>
    public bool Overwrite { get; set; } = false;
}

When you use this class as a parameter to an application service or a controller, it is automatically validated and a localized validation exception is thrown.

  • Do use fluent validations when dealing with complex data models with specific business rules such as validating relationships between multiple entities or validating user-input forms with numerous fields.

Example Input DTO shown at below. See Data Transfer Objects for design best practices.

[Serializable]
public class IncrementalExportInput
{
    /// <summary>
    /// Starting revision number of the model 
    /// </summary>
    [Range(1, uint.MaxValue)]
    public uint FromRevision { get; set; } = 1;

    /// <summary>
    /// End revision number of the model 
    /// </summary>
    [Range(1, uint.MaxValue)]
    public uint ToRevision { get; set; } = uint.MaxValue;

    /// <summary>
    /// Model authority set uri 
    /// </summary>
    public string ModelAuthoritySet { get; set; } = null;
}

This method is used to define validation rules for the IncrementalExportInput class. In this example, there are two rules defined:

  • The first rule checks the ModelAuthoritySet property and uses the Must method to define a custom validation rule called UriChecker. If the UriChecker method returns false, a localized error message is displayed.
  • The second rule checks the FromRevision property and ensures that it is less than the ToRevision property. It also provides a localized error message and an error code (OdmsErrorCodes.ValidationError).

The constructor takes an instance of IStringLocalizer as a parameter. This localizer is used to provide localized error messages for validation failures.

public class IncrementalExportInputValidator : AbstractValidator<IncrementalExportInput>
{
    private readonly IStringLocalizer<OdmsResource> _localizer;

    public IncrementalExportInputValidator(IStringLocalizer<OdmsResource> localizer)
    {
        _localizer = localizer;

        RuleFor(input => input.ModelAuthoritySet)
             .Must(uri => UriChecker(uri))
             .WithMessage(_localizer["Validator:Model:00003"].Value);

        RuleFor(input => input.FromRevision) // Revision 1
            .LessThan(input => input.ToRevision) // Revision 2
            .WithMessage(_localizer["Validator:Model:00004"].Value)
            .WithErrorCode(OdmsErrorCodes.ValidationError);
    }

    private bool UriChecker(string uri)
    {
        bool isValidUri = uri == null ? true :  // MAS value is optional value, check should be done when input value provided.
            Uri.TryCreate(uri, UriKind.Absolute, out var uriResult) && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps);

        return isValidUri;
    }
}