-
Notifications
You must be signed in to change notification settings - Fork 17
Description
I've been trying to use this project with a minimal API and I've been playing with making it NativeAOT. I found that there's a weird issue and got curious to figure out why.
This is the stack trace I got:
System.NotSupportedException: 'FluentValidation.IValidator`1[Microsoft.Extensions.Logging.Logger`1[Contoso.Runtime.IEndpoint]]' is missing native code or metadata. This can happen for code that is not compatible with trimming or AOT. Inspect and fix trimming and AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility
at System.Reflection.Runtime.General.TypeUnifier.WithVerifiedTypeHandle(RuntimeConstructedGenericTypeInfo, RuntimeTypeInfo[]) + 0x98
at System.Reflection.Runtime.TypeInfos.RuntimeTypeInfo.MakeGenericType(Type[]) + 0x248
at SharpGrip.FluentValidation.AutoValidation.Shared.Extensions.ServiceProviderExtensions.GetValidator(IServiceProvider, Type) + 0x6c
at SharpGrip.FluentValidation.AutoValidation.Endpoints.Filters.FluentValidationAutoValidationEndpointFilter.<InvokeAsync>d__0.MoveNext() + 0x2a0
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Http.Generated.<GeneratedRouteBuilderExtensions_g>F60C50E4107966576BFC90421C6592150AACC3F9288F7BF4F7F07549415ED8317__GeneratedRouteBuilderExtensionsCore.<>c__DisplayClass4_0.<<MapGet0>g__RequestHandlerFiltered|6>d.MoveNext() + 0x3d4
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<<Invoke>g__AwaitRequestTask|7_0>d.MoveNext() + 0x60
--- End of stack trace from previous location ---
at Contoso.Runtime.ExceptionMiddleware.<InvokeAsync>d__3.MoveNext() + 0x534
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.<Invoke>d__14.MoveNext() + 0x94
this is the minimal API code (trimmed for simplicity)
{
...
byDeviceSettingsGroup.MapGet("/", GetAvailableSettingsAsync).AddFluentValidationAutoValidation().ProducesProblem(StatusCodes.Status404NotFound);
...
}
private static async Task<IResult> GetAvailableSettingsAsync([FromServices] ILogger<IEndpoint> logger, string deviceId)
{
logger.LogWarning("Entering {fn} for device {deviceId}", nameof(GetAvailableSettingsAsync), deviceId);
return TypedResults.Ok();
}
So the error looked odd to me, why was it trying to find a Validator from a service injected, but it makes sense given the auto discovery nature... Anyway. I found that the main issue is the following:
Line 10 in a9c5045
return serviceProvider.GetService(typeof(IValidator<>).MakeGenericType(type)); |
called from
Line 19 in a9c5045
if (argument != null && argument.GetType().IsCustomType() && serviceProvider.GetValidator(argument.GetType()) is IValidator validator) |
The code above works normally with the JIT because the type is known at runtime, and we get null after asking the service provider to give us the service (because of course, there's no validator registered for the logger). But on NativeAOT / trimmed assemblies it fails to evaluate the type to ask for, because the type itself doesn't exist. So we basically fail before the GetService can return null
I don't really expect this to be fixed, to my knowledge, nowhere on this library says it's meant to be trimmable or nativeAOT but I thought I'd share my experience as it was a good learning exercise.