Skip to content

Dapper.AOT leaves trim-unsafe Dapper reflection paths reachable during Native AOT publish #2232

Description

@JamesNK

Check your library version, and try updating

This reproduces with Dapper 2.1.86 and Dapper.AOT 1.1.0, which are the versions currently used by the Aspire Native AOT dashboard work.

Describe the bug

Publishing a Dapper.AOT-enabled application with Native AOT produces trimming and AOT diagnostics from reachable code in the Dapper assembly. The application uses [module: DapperAot], includes Dapper.AOT at runtime for generated interceptors, and uses DynamicParameters populated with explicit scalar values. It does not use object parameter templates or SQL Server table-valued parameters.

The publish reports 16 distinct Dapper diagnostics. Here is the complete breakdown by warning ID and code path.

Warning breakdown

IL2070: unannotated Type parameters used for reflection (5 diagnostics)

  1. DefaultTypeMap.GetSettableProps(Type) calls Type.GetProperties with public and non-public binding flags. Its t parameter does not promise that those properties are preserved.
  2. DefaultTypeMap.GetSettableFields(Type) calls Type.GetFields with public and non-public binding flags. Its t parameter does not promise that those fields are preserved.
  3. StructuredHelper.CreateFor(Type, string, int) calls Type.GetProperty for two SQL Server data-record properties. Its type parameter does not promise that public properties are preserved. These two call sites produce separate diagnostics at SqlDataRecordListTVPParameter.cs:69 and :75.
  4. TypeExtensions.GetPublicInstanceMethod(Type, string, Type[]) calls Type.GetMethod. Its type parameter does not promise that public methods are preserved.

The common issue is missing DynamicallyAccessedMembers data flow. Annotating the incoming Type values may be appropriate where these reflection paths are intended to work after trimming. If the paths are unsupported under AOT, they could instead be isolated behind an appropriately annotated public boundary and kept unreachable from Dapper.AOT-generated paths.

/_/Dapper/TypeExtensions.cs(9): Trim analysis warning IL2070: Dapper.TypeExtensions.GetPublicInstanceMethod(Type,String,Type[]): 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to System.Type.GetMethod(...). The parameter 'type' does not have matching annotations.

IL2075: reflected types lose member-preservation requirements (4 diagnostics)

  1. DefaultTypeMap.GetPropertySetter(PropertyInfo, Type) reflects over PropertyInfo.DeclaringType. That return value does not guarantee public and non-public properties are preserved.
  2. SqlMapper.CreateParamInfoGenerator(...) calls GetProperties() on SqlMapper.Identity.ParametersType, but that property does not preserve public properties.
  3. The same method calls GetConstructors() on Identity.ParametersType, but the value does not preserve public constructors.
  4. The same method calls GetMethod(...) on PropertyInfo.PropertyType, but that value does not preserve public methods.

These warnings show that adding annotations only to local helper parameters may not be enough. The requirements need to flow through Identity.ParametersType and the property-type path, or the runtime parameter-object generator needs to be excluded when a generated Dapper.AOT interceptor handles the command.

/_/Dapper/SqlMapper.cs(2598): Trim analysis warning IL2075: Dapper.SqlMapper.CreateParamInfoGenerator(...): the return value of SqlMapper.Identity.ParametersType does not satisfy the PublicProperties requirement in System.Type.GetProperties().

IL3050: runtime code generation and generic construction (7 diagnostics)

  1. StructuredHelper.CreateFor(...) creates a DynamicMethod for SQL Server table-valued parameters.
  2. SqlMapper.CreateParamInfoGenerator(...) creates a DynamicMethod for runtime parameter-object access.
  3. SqlMapper.CreateParamInfoGenerator(...) also calls Type.MakeGenericType.
  4. SqlMapper.AddTypeHandlerCore(...) calls Type.MakeGenericType at three separate sites while constructing nullable/value-type handler adapters.
  5. SqlMapper.LookupDbType(...) calls Type.MakeGenericType while resolving a data-record handler.

DynamicMethod cannot work in Native AOT. MakeGenericType works only when the required closed generic instantiation was generated ahead of time. In this repro, the application does not use object parameter templates or SQL Server TVPs, so ideally the generated Dapper.AOT path would prevent these fallback implementations from being rooted. Any still-supported runtime path needs an AOT-safe implementation or explicit generic instantiation coverage.

/_/Dapper/SqlMapper.cs(2573): AOT analysis warning IL3050: Dapper.SqlMapper.CreateParamInfoGenerator(...): using DynamicMethod can break functionality when AOT compiling. Creating a DynamicMethod requires dynamic code.

To Reproduce

  1. Check out Enable Native AOT dashboard with Fluent UI v5 microsoft/aspire#19565 after its warning-visibility change is included.
  2. From the Aspire repository root, run:
.\restore.cmd
.\.dotnet\dotnet.exe publish src\Aspire.Dashboard\Aspire.Dashboard.csproj `
  -c Release -r win-x64 --self-contained true `
  -p:ContinuousIntegrationBuild=false
  1. Search the output for /_/Dapper/ or Dapper.SqlMapper.

The relevant project enables:

<PublishAot>true</PublishAot>
<TrimmerSingleWarn>false</TrimmerSingleWarn>
<InterceptorsNamespaces>$(InterceptorsNamespaces);Dapper.AOT</InterceptorsNamespaces>

The Dapper.AOT opt-in is in src/Aspire.Dashboard/ServiceClient/DashboardSqliteDatabase.cs. The dashboard's DynamicParameters usages are under src/Aspire.Dashboard/Otlp/Storage/.

Expected and actual behavior

Expected: supported Dapper.AOT usage publishes without diagnostics from Dapper's reflection/Reflection.Emit fallback implementation. Paths unsupported under Native AOT should either be removed from the reachable graph, annotated so the warnings stop at the appropriate public boundary, or replaced by AOT-safe paths.

Actual: reflection and dynamic-code implementation details remain reachable and produce IL2070, IL2075, and IL3050 warnings.

Additional context

The application uses SQLite through Microsoft.Data.Sqlite. The warnings include SQL Server TVP helper code even though that feature is not used, which suggests that more fallback implementation is retained than this usage requires.

Environment:

  • Windows 10.0.26200, win-x64
  • .NET SDK 11.0.100-rc.1.26425.128 (3551975be0)
  • Dapper 2.1.86
  • Dapper.AOT 1.1.0
  • Aspire commit ca26d2c4b5285508e07ee1b218ba0b36582d0e3e

I searched open and closed issues for Dapper.AOT trimming warnings and these specific members and did not find a matching report.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions