diff --git a/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.ValidationsGenerator/Emitters/ValidationsGenerator.Emitter.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.ValidationsGenerator/Emitters/ValidationsGenerator.Emitter.cs index 5d4e9fdaba5f..4d90dfbb5b1a 100644 --- a/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.ValidationsGenerator/Emitters/ValidationsGenerator.Emitter.cs +++ b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.ValidationsGenerator/Emitters/ValidationsGenerator.Emitter.cs @@ -7,6 +7,7 @@ using System.Text; using Microsoft.CodeAnalysis.CSharp; using System.IO; +using System.Text.RegularExpressions; namespace Microsoft.AspNetCore.Http.ValidationsGenerator; @@ -14,6 +15,7 @@ public sealed partial class ValidationsGenerator : IIncrementalGenerator { public static string GeneratedCodeConstructor => $@"global::System.CodeDom.Compiler.GeneratedCodeAttribute(""{typeof(ValidationsGenerator).Assembly.FullName}"", ""{typeof(ValidationsGenerator).Assembly.GetName().Version}"")"; public static string GeneratedCodeAttribute => $"[{GeneratedCodeConstructor}]"; + private static readonly Regex InvalidNameCharsRegex = new("[^0-9A-Za-z_]", RegexOptions.Compiled); internal static void Emit(SourceProductionContext context, (InterceptableLocation? AddValidation, ImmutableArray ValidatableTypes) emitInputs) { @@ -238,12 +240,7 @@ private static void EmitValidatableMemberForCreate(ValidatableProperty member, C private static string SanitizeTypeName(string typeName) { - // Replace invalid characters with underscores and remove generic notation - return typeName - .Replace(".", "_") - .Replace("<", "_") - .Replace(">", "_") - .Replace(",", "_") - .Replace(" ", "_"); + // Replace invalid characters with underscores + return InvalidNameCharsRegex.Replace(typeName, "_"); } } diff --git a/src/Http/Http.Extensions/test/ValidationsGenerator/ValidationsGenerator.Parameters.cs b/src/Http/Http.Extensions/test/ValidationsGenerator/ValidationsGenerator.Parameters.cs index 7494e27efa2f..f05f80999147 100644 --- a/src/Http/Http.Extensions/test/ValidationsGenerator/ValidationsGenerator.Parameters.cs +++ b/src/Http/Http.Extensions/test/ValidationsGenerator/ValidationsGenerator.Parameters.cs @@ -28,7 +28,7 @@ public async Task CanValidateParameters() var app = builder.Build(); -app.MapGet("/params", ( +app.MapPost("/params", ( // Skipped from validation because it is resolved as a service by IServiceProviderIsService TestService testService, // Skipped from validation because it is marked as a [FromKeyedService] parameter @@ -39,7 +39,8 @@ public async Task CanValidateParameters() [CustomValidation(ErrorMessage = "Value must be an even number")] int value4 = 4, [CustomValidation, Range(10, 100)] int value5 = 10, // Skipped from validation because it is marked as a [FromService] parameter - [FromServices] [Range(10, 100)] int? value6 = 4) => "OK"); + [FromServices] [Range(10, 100)] int? value6 = 4, + Dictionary? testDict = null) => "OK"); app.Run(); diff --git a/src/Http/Http.Extensions/test/ValidationsGenerator/snapshots/ValidationsGeneratorTests.CanValidateParameters#ValidatableInfoResolver.g.verified.cs b/src/Http/Http.Extensions/test/ValidationsGenerator/snapshots/ValidationsGeneratorTests.CanValidateParameters#ValidatableInfoResolver.g.verified.cs index 2b7c2a0c272d..97eeacbed294 100644 --- a/src/Http/Http.Extensions/test/ValidationsGenerator/snapshots/ValidationsGeneratorTests.CanValidateParameters#ValidatableInfoResolver.g.verified.cs +++ b/src/Http/Http.Extensions/test/ValidationsGenerator/snapshots/ValidationsGeneratorTests.CanValidateParameters#ValidatableInfoResolver.g.verified.cs @@ -67,6 +67,11 @@ public bool TryGetValidatableTypeInfo(global::System.Type type, [global::System. validatableInfo = CreateTestService(); return true; } + if (type == typeof(global::System.Collections.Generic.Dictionary)) + { + validatableInfo = CreateDictionary_2(); + return true; + } return false; } @@ -92,6 +97,38 @@ private ValidatableTypeInfo CreateTestService() ] ); } + private ValidatableTypeInfo CreateDictionary_2() + { + return new GeneratedValidatableTypeInfo( + type: typeof(global::System.Collections.Generic.Dictionary), + members: [ + new GeneratedValidatablePropertyInfo( + containingType: typeof(global::System.Collections.Generic.Dictionary), + propertyType: typeof(global::System.Collections.Generic.ICollection), + name: "System.Collections.Generic.IDictionary.Values", + displayName: "System.Collections.Generic.IDictionary.Values" + ), + new GeneratedValidatablePropertyInfo( + containingType: typeof(global::System.Collections.Generic.Dictionary), + propertyType: typeof(global::System.Collections.Generic.IEnumerable), + name: "System.Collections.Generic.IReadOnlyDictionary.Values", + displayName: "System.Collections.Generic.IReadOnlyDictionary.Values" + ), + new GeneratedValidatablePropertyInfo( + containingType: typeof(global::System.Collections.Generic.Dictionary), + propertyType: typeof(global::TestService), + name: "this[]", + displayName: "this[]" + ), + new GeneratedValidatablePropertyInfo( + containingType: typeof(global::System.Collections.Generic.Dictionary), + propertyType: typeof(global::System.Collections.ICollection), + name: "System.Collections.IDictionary.Values", + displayName: "System.Collections.IDictionary.Values" + ), + ] + ); + } }