RSCG – Microsoft.Extensions.Options.Generators.OptionsValidatorGenerator

RSCG – Microsoft.Extensions.Options.Generators.OptionsValidatorGenerator    

name Microsoft.Extensions.Options.Generators.OptionsValidatorGenerator
nuget https://www.nuget.org/packages/Microsoft.Extensions.Options
link https://learn.microsoft.com/en-us/dotnet/core/extensions/options-validation-generator
author Microsoft

Generating the validation for data annotations on options classes.

 

This is how you can use Microsoft.Extensions.Options.Generators.OptionsValidatorGenerator .

The code that you start with is

  <Project Sdk="Microsoft.NET.Sdk">    <PropertyGroup>     <TargetFramework>net8.0</TargetFramework>     <ImplicitUsings>enable</ImplicitUsings>     <Nullable>enable</Nullable>   </PropertyGroup> 	<ItemGroup> 		<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.0" /> 	</ItemGroup> 	<PropertyGroup> 		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> 		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath> 	</PropertyGroup> 	 </Project>   

The code that you will use is

  namespace DemoValidatorObj;  [OptionsValidator] public partial class ValidatorForMyApp     : IValidateOptions<MyAppOptions> { }  //public class SecondModelNoNamespace //{ //    [Required] //    [MinLength(5)] //    public string P4 { get; set; } = string.Empty; //}   //[OptionsValidator] //public partial class SecondValidatorNoNamespace //    : IValidateOptions<SecondModelNoNamespace> //{ //}     
  namespace DemoValidatorObj;  [DebuggerDisplay("{AppDisplayName}")] public class MyAppOptions {     public const string ConfigName = "MyAppOptionsInConfig";     [Required]     [MinLength(3)]     public string AppDisplayName { get; set; } = string.Empty;      //[ValidateObjectMembers(     //    typeof(SecondValidatorNoNamespace))]     //public SecondModelNoNamespace? P2 { get; set; } }  //[OptionsValidator] //public partial class SecondValidatorNoNamespace //    : IValidateOptions<SecondModelNoNamespace> //{ //}  

  The code that is generated is

      // <auto-generated/>     #nullable enable     #pragma warning disable CS1591 // Compensate for https://github.com/dotnet/roslyn/issues/54103     namespace DemoValidatorObj {     partial class ValidatorForMyApp     {         /// <summary>         /// Validates a specific named options instance (or all when <paramref name="name"/> is <see langword="null" />).         /// </summary>         /// <param name="name">The name of the options instance being validated.</param>         /// <param name="options">The options instance.</param>         /// <returns>Validation result.</returns>         [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "8.0.9.3103")]         [System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("Trimming", "IL2026:RequiresUnreferencedCode",              Justification = "The created ValidationContext object is used in a way that never call reflection")]         public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::DemoValidatorObj.MyAppOptions options)         {             global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null;             var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options);             var validationResults = new global::System.Collections.Generic.List<global::System.ComponentModel.DataAnnotations.ValidationResult>();             var validationAttributes = new global::System.Collections.Generic.List<global::System.ComponentModel.DataAnnotations.ValidationAttribute>(2);              context.MemberName = "AppDisplayName";             context.DisplayName = string.IsNullOrEmpty(name) ? "MyAppOptions.AppDisplayName" : $"{name}.AppDisplayName";             validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1);             validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2);             if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.AppDisplayName, context, validationResults, validationAttributes))             {                 (builder ??= new()).AddResults(validationResults);             }              return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build();         }     } } namespace __OptionValidationStaticInstances {     [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "8.0.9.3103")]     file static class __Attributes     {         internal static readonly global::System.ComponentModel.DataAnnotations.RequiredAttribute A1 = new global::System.ComponentModel.DataAnnotations.RequiredAttribute();          internal static readonly __OptionValidationGeneratedAttributes.__SourceGen__MinLengthAttribute A2 = new __OptionValidationGeneratedAttributes.__SourceGen__MinLengthAttribute(             (int)3);     } } namespace __OptionValidationStaticInstances {     [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "8.0.9.3103")]     file static class __Validators     {     } } namespace __OptionValidationGeneratedAttributes {     [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "8.0.9.3103")]     [global::System.AttributeUsage(global::System.AttributeTargets.Property | global::System.AttributeTargets.Field | global::System.AttributeTargets.Parameter, AllowMultiple = false)]     file class __SourceGen__MinLengthAttribute : global::System.ComponentModel.DataAnnotations.ValidationAttribute     {         private static string DefaultErrorMessageString => "The field {0} must be a string or array type with a minimum length of '{1}'.";          public __SourceGen__MinLengthAttribute(int length) : base(() => DefaultErrorMessageString) { Length = length; }         public int Length { get; }         public override bool IsValid(object? value)         {             if (Length < -1)             {                 throw new global::System.InvalidOperationException("MinLengthAttribute must have a Length value that is zero or greater.");             }             if (value == null)             {                 return true;             }              int length;             if (value is string stringValue)             {                 length = stringValue.Length;             }             else if (value is System.Collections.ICollection collectionValue)             {                 length = collectionValue.Count;             }             else             {                 throw new global::System.InvalidCastException($"The field of type {value.GetType()} must be a string, array, or ICollection type.");             }              return length >= Length;         }         public override string FormatErrorMessage(string name) => string.Format(global::System.Globalization.CultureInfo.CurrentCulture, ErrorMessageString, name, Length);     } }  

Code and pdf at https://ignatandrei.github.io/RSCG_Examples/v2/docs/Microsoft.Extensions.Options.Generators.OptionsValidatorGenerator