Dapper.AOT leaves trim-unsafe Dapper reflection paths reachable during Native AOT publish
Nobody has claimed this yet.
- Dominant language
- C#
- Stars
- 18.4k
- Forks
- 3.7k
- Avg merge
- 5h 8m
- Merged PRs (30d)
- 1
Description
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)
DefaultTypeMap.GetSettableProps(Type)callsType.GetPropertieswith public and non-public binding flags. Itstparameter does not promise that those properties are preserved.DefaultTypeMap.GetSettableFields(Type)callsType.GetFieldswith public and non-public binding flags. Itstparameter does not promise that those fields are preserved.StructuredHelper.CreateFor(Type, string, int)callsType.GetPropertyfor two SQL Server data-record properties. Itstypeparameter does not promise that public properties are preserved. These two call sites produce separate diagnostics atSqlDataRecordListTVPParameter.cs:69and:75.TypeExtensions.GetPublicInstanceMethod(Type, string, Type[])callsType.GetMethod. Itstypeparameter 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)
DefaultTypeMap.GetPropertySetter(PropertyInfo, Type)reflects overPropertyInfo.DeclaringType. That return value does not guarantee public and non-public properties are preserved.SqlMapper.CreateParamInfoGenerator(...)callsGetProperties()onSqlMapper.Identity.ParametersType, but that property does not preserve public properties.- The same method calls
GetConstructors()onIdentity.ParametersType, but the value does not preserve public constructors. - The same method calls
GetMethod(...)onPropertyInfo.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)
StructuredHelper.CreateFor(...)creates aDynamicMethodfor SQL Server table-valued parameters.SqlMapper.CreateParamInfoGenerator(...)creates aDynamicMethodfor runtime parameter-object access.SqlMapper.CreateParamInfoGenerator(...)also callsType.MakeGenericType.SqlMapper.AddTypeHandlerCore(...)callsType.MakeGenericTypeat three separate sites while constructing nullable/value-type handler adapters.SqlMapper.LookupDbType(...)callsType.MakeGenericTypewhile 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
- Check out https://github.com/microsoft/aspire/pull/19565 after its warning-visibility change is included.
- 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
- Search the output for
/_/Dapper/orDapper.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.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with TypeExtensions.cs, SqlMapper.cs, and SqlDataRecordListTVPParameter.cs, then reproduce the warnings using the Aspire.Dashboard publish command. Trace the reflection and DynamicMethod paths from the listed diagnostics, including the Dapper.AOT opt-in in DashboardSqliteDatabase.cs and DynamicParameters usages under Otlp/Storage/. Done means supported Dapper.AOT usage publishes without the reported diagnostics.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- backend, build-system, databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100