Skip to content

NativeAOT hiccups #66

@devtekve

Description

@devtekve

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:

return serviceProvider.GetService(typeof(IValidator<>).MakeGenericType(type));

called from
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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions