| File: src\Shared\Data.Validation\TimeSpanAttribute.cs | Web Access |
| Project: src\src\Libraries\Microsoft.Extensions.Diagnostics.HealthChecks.ResourceUtilization\Microsoft.Extensions.Diagnostics.HealthChecks.ResourceUtilization.csproj (Microsoft.Extensions.Diagnostics.HealthChecks.ResourceUtilization) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.ComponentModel.DataAnnotations; using System.Diagnostics.CodeAnalysis; using System.Globalization; using Microsoft.Shared.Diagnostics; #pragma warning disable CA1716 namespace Microsoft.Shared.Data.Validation; #pragma warning restore CA1716 /// <summary> /// Provides boundary validation for <see cref="TimeSpan"/>. /// </summary> #if !SHARED_PROJECT [ExcludeFromCodeCoverage] #endif [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)] [SuppressMessage("Design", "CA1019:Define accessors for attribute arguments", Justification = "Indirectly we are.")] internal sealed class TimeSpanAttribute : ValidationAttribute { /// <summary> /// Gets the lower bound for time span. /// </summary> public TimeSpan Minimum => _minMs.HasValue ? TimeSpan.FromMilliseconds((double)_minMs) : TimeSpan.Parse(_min!, CultureInfo.InvariantCulture); /// <summary> /// Gets the upper bound for time span. /// </summary> public TimeSpan? Maximum { get { if (_maxMs.HasValue) { return TimeSpan.FromMilliseconds((double)_maxMs); } else { return _max == null ? null : TimeSpan.Parse(_max, CultureInfo.InvariantCulture); } } } /// <summary> /// Gets or sets a value indicating whether the time span validation should exclude the minimum and maximum values. /// </summary> /// <value> /// The default value is <c>false</c>. /// </value> public bool Exclusive { get; set; } private readonly int? _minMs; private readonly int? _maxMs; private readonly string? _min; private readonly string? _max; /// <summary> /// Initializes a new instance of the <see cref="TimeSpanAttribute"/> class. /// </summary> /// <param name="minMs">Minimum in milliseconds.</param> public TimeSpanAttribute(int minMs) { _minMs = minMs; _maxMs = null; } /// <summary> /// Initializes a new instance of the <see cref="TimeSpanAttribute"/> class. /// </summary> /// <param name="minMs">Minimum in milliseconds.</param> /// <param name="maxMs">Maximum in milliseconds.</param> public TimeSpanAttribute(int minMs, int maxMs) { _minMs = minMs; _maxMs = maxMs; } /// <summary> /// Initializes a new instance of the <see cref="TimeSpanAttribute"/> class. /// </summary> /// <param name="min">Minimum represented as time span string.</param> public TimeSpanAttribute(string min) { _ = Throw.IfNullOrWhitespace(min); _min = min; _max = null; } /// <summary> /// Initializes a new instance of the <see cref="TimeSpanAttribute"/> class. /// </summary> /// <param name="min">Minimum represented as time span string.</param> /// <param name="max">Maximum represented as time span string.</param> public TimeSpanAttribute(string min, string max) { _ = Throw.IfNullOrWhitespace(min); _ = Throw.IfNullOrWhitespace(max); _min = min; _max = max; } /// <summary> /// Validates that a given value represents an in-range TimeSpan value. /// </summary> /// <param name="value">The value to validate.</param> /// <param name="validationContext">Additional context for this validation.</param> /// <returns>A value indicating success or failure.</returns> protected override ValidationResult IsValid(object? value, ValidationContext? validationContext) { var min = Minimum; var max = Maximum; if (min >= max) { throw new InvalidOperationException($"{nameof(TimeSpanAttribute)} requires that the minimum value be less than the maximum value (see field {validationContext.GetDisplayName()})"); } if (value == null) { // use the [Required] attribute to force presence return ValidationResult.Success!; } if (value is TimeSpan ts) { if (Exclusive && ts <= min) { return new ValidationResult($"The field {validationContext.GetDisplayName()} must be > to {min}.", validationContext.GetMemberName()); } if (ts < min) { return new ValidationResult($"The field {validationContext.GetDisplayName()} must be >= to {min}.", validationContext.GetMemberName()); } if (max.HasValue) { if (Exclusive && ts >= max.Value) { return new ValidationResult($"The field {validationContext.GetDisplayName()} must be < to {max}.", validationContext.GetMemberName()); } if (ts > max.Value) { return new ValidationResult($"The field {validationContext.GetDisplayName()} must be <= to {max}.", validationContext.GetMemberName()); } } return ValidationResult.Success!; } throw new InvalidOperationException($"{nameof(TimeSpanAttribute)} can only be used with fields of type TimeSpan (see field {validationContext.GetDisplayName()})"); } }