Die integrierte Validierung der .NET Minimal APIs funktioniert nicht mehr, wenn sich die Endpunktzuordnung in einer andeC#

Ein Treffpunkt für C#-Programmierer
Anonymous
 Die integrierte Validierung der .NET Minimal APIs funktioniert nicht mehr, wenn sich die Endpunktzuordnung in einer ande

Post by Anonymous »

Ich verwende die integrierte Minimal-API-Validierung (

Code: Select all

AddValidation()
+ Datenanmerkungen / generierte Resolver).
Ich habe einen modularen Aufbau mit mehreren Baugruppen:
  • Host (

    Code: Select all

    Host.Api
    ) – der Einstiegspunkt, an dem die DI-Verkabelung erfolgt (

    Code: Select all

    Program.cs
    )
  • Funktion (

    Code: Select all

    Feature.Users
    ) – enthält Slices/Endpunktdefinitionen + DTOs
  • Geteilt (

    Code: Select all

    Shared.Endpoints
    ) – enthält eigenwillige MapPost-Wrapper/-Konventionen (CQRS-Stil)
Ich habe diese Frage zuvor gelesen und sie verwendet, um die Validierung zum Laufen zu bringen, wenn sich Endpunkte/DTOs in einer anderen Assembly befinden:
Eingebaute Validierungsunterstützung für Minimal-APIs
Diese Frage hat mir geholfen zu verstehen, dass Validierungsmetadaten pro Assembly generiert werden und ich möglicherweise Resolver von anderen registrieren muss Assemblies.
Szenario Nr. 1: Endpunkt direkt in der Feature-Assembly zugeordnet (funktioniert)

Code: Select all

// App.FeatureA
public static class FeatureAEndpoints
{
public static void Map(IEndpointRouteBuilder app)
{
app.MapPost("/items", (CreateItemRequest request) => Results.Ok());
}
}

public sealed class CreateItemRequest
{
[Required]
public string? Name { get; set; }
}
In App.Host funktioniert die Validierung, wenn ich Validierungs-Resolver aus Feature-Assemblys aggregiere:

Code: Select all

builder.Services.AddValidation(options =>
{
foreach (var resolver in DiscoverResolvers(typeof(FeatureAEndpoints).Assembly))
options.Resolvers.Add(resolver);
});

static IEnumerable DiscoverResolvers(Assembly assembly) =>
assembly.GetTypes()
.Where(t => typeof(IValidatableInfoResolver).IsAssignableFrom(t)
&& !t.IsAbstract
&& t.GetConstructor(Type.EmptyTypes) != null)
.Select(t => (IValidatableInfoResolver)Activator.CreateInstance(t)!);
Dies entspricht der Beschreibung der verknüpften Frage.
Hinweis: Die Feature-Assembly muss auch einen .AddValidation()-Aufruf enthalten (auch wenn in meinem Code nicht direkt darauf verwiesen wird!), damit der Validierungsquellengenerator für diese Assembly ausgeführt wird. Andernfalls ist möglicherweise kein IValidatableInfoResolver vorhanden, der durch Scannen ermittelt werden kann.
Zum Beispiel musste ich diese Datei zu dieser Assembly hinzufügen:

Code: Select all

/// 
/// Required so validation source generation sees an .AddValidation() inside this assembly.
/// See https://github.com/dotnet/AspNetCore.Docs/issues/35090#issuecomment-3661156506
/// 
internal static class ValidationCodegenTrigger
{
public static IServiceCollection Trigger(this IServiceCollection services)
=> services.AddValidation();
}
Szenario Nr. 2: Endpunkt über gemeinsame generische Erweiterung zugeordnet (Validierungsunterbrechungen)
Jetzt verschiebe ich den eigentlichen MapPost-Aufruf in eine gemeinsam genutzte Bibliothek:

Code: Select all

// App.FeatureA
public static class FeatureAEndpoints
{
public static void Map(IEndpointRouteBuilder app)
{
app.MapCommand("/items"); //it's calling an extension method
}
}

public sealed class CreateItemRequest
{
[Required]
public string? Name { get; set; }
}
Und in der anderen Assembly wird der eigentliche Endpunkt zugeordnet und DTO als generische TRequest in den Endpunkt aufgenommen:

Code: Select all

// App.SharedEndpoints
public static class CommandEndpointExtensions
{
public static RouteHandlerBuilder MapCommand(
this IEndpointRouteBuilder app,
string pattern)
where TRequest : class
{
return app.MapPost(pattern, (TRequest request) => Results.Ok());
}
}
Beobachtetes Verhalten:
  • JSON-Bindung funktioniert
  • OpenAPI-Generierung funktioniert
  • Endpunkt wird ausgeführt
  • Validierung wird nicht mehr ausgeführt (ungültige Anfragen geben nicht 400 zurück)
Auch wenn ich die Resolver-Aggregationslogik behalte Szenario Nr. 1, die Validierung wird immer noch nicht ausgelöst.
Fragen
  • Warum funktioniert die integrierte Minimal-API-Validierung in Szenario Nr. 2 nicht mehr?
  • Warum reicht „Resolver aus anderen Assemblys scannen und registrieren“ hier nicht aus?
  • Was sind die richtigen Problemumgehungen und wann sind sie jeweils erforderlich?

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post