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
[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
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;
}
}