Skip to content

Commit 03e1b28

Browse files
committed
Do not mark the .NET 8.0 TFMs as AOT-compatible and use TypeDescriptor.RegisterType<T>()/TypeDescriptor.GetConverterFromRegisteredType() on .NET 9.0+
1 parent 945fc9d commit 03e1b28

14 files changed

+284
-69
lines changed

Directory.Build.targets

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,15 @@
1616
</PropertyGroup>
1717

1818
<!--
19-
Note: the trimming and Native AOT analyzers are only supported on .NET.
19+
Note: the trimming and Native AOT analyzers are only supported on .NET. Since the OpenIddict
20+
Entity Framework 6.x and Entity Framework Core stores internally use new trimming/AOT-friendly
21+
TypeDescriptor APIs introduced in .NET 9.0, only the .NET 9.0+ TFMs are marked as AOT-compatible.
2022
-->
2123

2224
<PropertyGroup
23-
Condition=" $(RepoRelativeProjectDir.Contains('src')) And '$(TargetFrameworkIdentifier)' == '.NETCoreApp' ">
25+
Condition=" $(RepoRelativeProjectDir.Contains('src')) And
26+
'$(TargetFrameworkIdentifier)' == '.NETCoreApp' And
27+
$([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), '9.0')) ">
2428
<IsAotCompatible>true</IsAotCompatible>
2529
</PropertyGroup>
2630

@@ -112,6 +116,7 @@
112116
<DefineConstants>$(DefineConstants);SUPPORTS_CERTIFICATE_LOADER</DefineConstants>
113117
<DefineConstants>$(DefineConstants);SUPPORTS_JSON_ELEMENT_DEEP_EQUALS</DefineConstants>
114118
<DefineConstants>$(DefineConstants);SUPPORTS_JSON_ELEMENT_PROPERTY_COUNT</DefineConstants>
119+
<DefineConstants>$(DefineConstants);SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION</DefineConstants>
115120
</PropertyGroup>
116121

117122
<PropertyGroup

src/OpenIddict.Client/OpenIddictClientDispatcher.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ async ValueTask<bool> IsActiveAsync(OpenIddictClientHandlerDescriptor descriptor
121121
{
122122
for (var index = 0; index < descriptor.FilterTypes.Length; index++)
123123
{
124-
if (!(_provider.GetService(descriptor.FilterTypes[index]) is IOpenIddictClientHandlerFilter<TContext> filter))
124+
if (_provider.GetService(descriptor.FilterTypes[index]) is not IOpenIddictClientHandlerFilter<TContext> filter)
125125
{
126126
throw new InvalidOperationException(SR.FormatID0099(descriptor.FilterTypes[index]));
127127
}

src/OpenIddict.EntityFramework/OpenIddictEntityFrameworkBuilder.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,15 @@ public OpenIddictEntityFrameworkBuilder ReplaceDefaultEntities<
7676
throw new InvalidOperationException(SR.GetResourceString(SR.ID0277));
7777
}
7878

79+
#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION
80+
// If the specified key type isn't a string (which is special-cased by the stores to avoid having to resolve
81+
// a TypeDescriptor instance) and the platform supports type registration, register the key type to ensure the
82+
// TypeDescriptor associated with that type will be preserved by the IL Linker and can be resolved at runtime.
83+
if (typeof(TKey) != typeof(string))
84+
{
85+
TypeDescriptor.RegisterType<TKey>();
86+
}
87+
#endif
7988
Services.Replace(ServiceDescriptor.Scoped<IOpenIddictApplicationManager>(static provider =>
8089
provider.GetRequiredService<OpenIddictApplicationManager<TApplication>>()));
8190
Services.Replace(ServiceDescriptor.Scoped<IOpenIddictAuthorizationManager>(static provider =>

src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkApplicationStore.cs

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,11 +1174,23 @@ public virtual async ValueTask UpdateAsync(TApplication application, Cancellatio
11741174
return default;
11751175
}
11761176

1177-
return (TKey?) GetConverter().ConvertFromInvariantString(identifier);
1177+
// Optimization: if the key is a string, directly return it as-is.
1178+
if (typeof(TKey) == typeof(string))
1179+
{
1180+
return (TKey?) (object?) identifier;
1181+
}
11781182

1179-
[UnconditionalSuppressMessage("Trimming", "IL2026",
1180-
Justification = "Only primitive types are supported as entity keys.")]
1181-
static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey));
1183+
else
1184+
{
1185+
var converter =
1186+
#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION
1187+
TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey));
1188+
#else
1189+
TypeDescriptor.GetConverter(typeof(TKey));
1190+
#endif
1191+
1192+
return (TKey?) converter.ConvertFromInvariantString(identifier);
1193+
}
11821194
}
11831195

11841196
/// <summary>
@@ -1193,10 +1205,22 @@ public virtual async ValueTask UpdateAsync(TApplication application, Cancellatio
11931205
return null;
11941206
}
11951207

1196-
return GetConverter().ConvertToInvariantString(identifier);
1208+
// Optimization: if the key is a string, directly return it as-is.
1209+
if (identifier is string value)
1210+
{
1211+
return value;
1212+
}
11971213

1198-
[UnconditionalSuppressMessage("Trimming", "IL2026",
1199-
Justification = "Only primitive types are supported as entity keys.")]
1200-
static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey));
1214+
else
1215+
{
1216+
var converter =
1217+
#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION
1218+
TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey));
1219+
#else
1220+
TypeDescriptor.GetConverter(typeof(TKey));
1221+
#endif
1222+
1223+
return converter.ConvertToInvariantString(identifier);
1224+
}
12011225
}
12021226
}

src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkAuthorizationStore.cs

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -975,11 +975,23 @@ public virtual async ValueTask UpdateAsync(TAuthorization authorization, Cancell
975975
return default;
976976
}
977977

978-
return (TKey?) GetConverter().ConvertFromInvariantString(identifier);
978+
// Optimization: if the key is a string, directly return it as-is.
979+
if (typeof(TKey) == typeof(string))
980+
{
981+
return (TKey?) (object?) identifier;
982+
}
983+
984+
else
985+
{
986+
var converter =
987+
#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION
988+
TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey));
989+
#else
990+
TypeDescriptor.GetConverter(typeof(TKey));
991+
#endif
979992

980-
[UnconditionalSuppressMessage("Trimming", "IL2026",
981-
Justification = "Only primitive types are supported as entity keys.")]
982-
static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey));
993+
return (TKey?) converter.ConvertFromInvariantString(identifier);
994+
}
983995
}
984996

985997
/// <summary>
@@ -994,10 +1006,22 @@ public virtual async ValueTask UpdateAsync(TAuthorization authorization, Cancell
9941006
return null;
9951007
}
9961008

997-
return GetConverter().ConvertToInvariantString(identifier);
1009+
// Optimization: if the key is a string, directly return it as-is.
1010+
if (identifier is string value)
1011+
{
1012+
return value;
1013+
}
1014+
1015+
else
1016+
{
1017+
var converter =
1018+
#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION
1019+
TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey));
1020+
#else
1021+
TypeDescriptor.GetConverter(typeof(TKey));
1022+
#endif
9981023

999-
[UnconditionalSuppressMessage("Trimming", "IL2026",
1000-
Justification = "Only primitive types are supported as entity keys.")]
1001-
static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey));
1024+
return converter.ConvertToInvariantString(identifier);
1025+
}
10021026
}
10031027
}

src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkScopeStore.cs

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -758,11 +758,23 @@ public virtual async ValueTask UpdateAsync(TScope scope, CancellationToken cance
758758
return default;
759759
}
760760

761-
return (TKey?) GetConverter().ConvertFromInvariantString(identifier);
761+
// Optimization: if the key is a string, directly return it as-is.
762+
if (typeof(TKey) == typeof(string))
763+
{
764+
return (TKey?) (object?) identifier;
765+
}
762766

763-
[UnconditionalSuppressMessage("Trimming", "IL2026",
764-
Justification = "Only primitive types are supported as entity keys.")]
765-
static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey));
767+
else
768+
{
769+
var converter =
770+
#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION
771+
TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey));
772+
#else
773+
TypeDescriptor.GetConverter(typeof(TKey));
774+
#endif
775+
776+
return (TKey?) converter.ConvertFromInvariantString(identifier);
777+
}
766778
}
767779

768780
/// <summary>
@@ -777,10 +789,22 @@ public virtual async ValueTask UpdateAsync(TScope scope, CancellationToken cance
777789
return null;
778790
}
779791

780-
return GetConverter().ConvertToInvariantString(identifier);
792+
// Optimization: if the key is a string, directly return it as-is.
793+
if (identifier is string value)
794+
{
795+
return value;
796+
}
781797

782-
[UnconditionalSuppressMessage("Trimming", "IL2026",
783-
Justification = "Only primitive types are supported as entity keys.")]
784-
static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey));
798+
else
799+
{
800+
var converter =
801+
#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION
802+
TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey));
803+
#else
804+
TypeDescriptor.GetConverter(typeof(TKey));
805+
#endif
806+
807+
return converter.ConvertToInvariantString(identifier);
808+
}
785809
}
786810
}

src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkTokenStore.cs

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,11 +1139,23 @@ public virtual async ValueTask UpdateAsync(TToken token, CancellationToken cance
11391139
return default;
11401140
}
11411141

1142-
return (TKey?) GetConverter().ConvertFromInvariantString(identifier);
1142+
// Optimization: if the key is a string, directly return it as-is.
1143+
if (typeof(TKey) == typeof(string))
1144+
{
1145+
return (TKey?) (object?) identifier;
1146+
}
1147+
1148+
else
1149+
{
1150+
var converter =
1151+
#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION
1152+
TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey));
1153+
#else
1154+
TypeDescriptor.GetConverter(typeof(TKey));
1155+
#endif
11431156

1144-
[UnconditionalSuppressMessage("Trimming", "IL2026",
1145-
Justification = "Only primitive types are supported as entity keys.")]
1146-
static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey));
1157+
return (TKey?) converter.ConvertFromInvariantString(identifier);
1158+
}
11471159
}
11481160

11491161
/// <summary>
@@ -1158,10 +1170,22 @@ public virtual async ValueTask UpdateAsync(TToken token, CancellationToken cance
11581170
return null;
11591171
}
11601172

1161-
return GetConverter().ConvertToInvariantString(identifier);
1173+
// Optimization: if the key is a string, directly return it as-is.
1174+
if (identifier is string value)
1175+
{
1176+
return value;
1177+
}
1178+
1179+
else
1180+
{
1181+
var converter =
1182+
#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION
1183+
TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey));
1184+
#else
1185+
TypeDescriptor.GetConverter(typeof(TKey));
1186+
#endif
11621187

1163-
[UnconditionalSuppressMessage("Trimming", "IL2026",
1164-
Justification = "Only primitive types are supported as entity keys.")]
1165-
static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey));
1188+
return converter.ConvertToInvariantString(identifier);
1189+
}
11661190
}
11671191
}

src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreBuilder.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,15 @@ public OpenIddictEntityFrameworkCoreBuilder ReplaceDefaultEntities<
8989
where TToken : OpenIddictEntityFrameworkCoreToken<TKey, TApplication, TAuthorization>
9090
where TKey : notnull, IEquatable<TKey>
9191
{
92+
#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION
93+
// If the specified key type isn't a string (which is special-cased by the stores to avoid having to resolve
94+
// a TypeDescriptor instance) and the platform supports type registration, register the key type to ensure the
95+
// TypeDescriptor associated with that type will be preserved by the IL Linker and can be resolved at runtime.
96+
if (typeof(TKey) != typeof(string))
97+
{
98+
TypeDescriptor.RegisterType<TKey>();
99+
}
100+
#endif
92101
Services.Replace(ServiceDescriptor.Scoped<IOpenIddictApplicationManager>(static provider =>
93102
provider.GetRequiredService<OpenIddictApplicationManager<TApplication>>()));
94103
Services.Replace(ServiceDescriptor.Scoped<IOpenIddictAuthorizationManager>(static provider =>

src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreApplicationStore.cs

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,11 +1255,23 @@ public virtual async ValueTask UpdateAsync(TApplication application, Cancellatio
12551255
return default;
12561256
}
12571257

1258-
return (TKey?) GetConverter().ConvertFromInvariantString(identifier);
1258+
// Optimization: if the key is a string, directly return it as-is.
1259+
if (typeof(TKey) == typeof(string))
1260+
{
1261+
return (TKey?) (object?) identifier;
1262+
}
12591263

1260-
[UnconditionalSuppressMessage("Trimming", "IL2026",
1261-
Justification = "Only primitive types are supported as entity keys.")]
1262-
static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey));
1264+
else
1265+
{
1266+
var converter =
1267+
#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION
1268+
TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey));
1269+
#else
1270+
TypeDescriptor.GetConverter(typeof(TKey));
1271+
#endif
1272+
1273+
return (TKey?) converter.ConvertFromInvariantString(identifier);
1274+
}
12631275
}
12641276

12651277
/// <summary>
@@ -1274,10 +1286,22 @@ public virtual async ValueTask UpdateAsync(TApplication application, Cancellatio
12741286
return null;
12751287
}
12761288

1277-
return GetConverter().ConvertToInvariantString(identifier);
1289+
// Optimization: if the key is a string, directly return it as-is.
1290+
if (identifier is string value)
1291+
{
1292+
return value;
1293+
}
12781294

1279-
[UnconditionalSuppressMessage("Trimming", "IL2026",
1280-
Justification = "Only primitive types are supported as entity keys.")]
1281-
static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey));
1295+
else
1296+
{
1297+
var converter =
1298+
#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION
1299+
TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey));
1300+
#else
1301+
TypeDescriptor.GetConverter(typeof(TKey));
1302+
#endif
1303+
1304+
return converter.ConvertToInvariantString(identifier);
1305+
}
12821306
}
12831307
}

src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreAuthorizationStore.cs

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,11 +1182,23 @@ public virtual async ValueTask UpdateAsync(TAuthorization authorization, Cancell
11821182
return default;
11831183
}
11841184

1185-
return (TKey?) GetConverter().ConvertFromInvariantString(identifier);
1185+
// Optimization: if the key is a string, directly return it as-is.
1186+
if (typeof(TKey) == typeof(string))
1187+
{
1188+
return (TKey?) (object?) identifier;
1189+
}
1190+
1191+
else
1192+
{
1193+
var converter =
1194+
#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION
1195+
TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey));
1196+
#else
1197+
TypeDescriptor.GetConverter(typeof(TKey));
1198+
#endif
11861199

1187-
[UnconditionalSuppressMessage("Trimming", "IL2026",
1188-
Justification = "Only primitive types are supported as entity keys.")]
1189-
static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey));
1200+
return (TKey?) converter.ConvertFromInvariantString(identifier);
1201+
}
11901202
}
11911203

11921204
/// <summary>
@@ -1201,10 +1213,22 @@ public virtual async ValueTask UpdateAsync(TAuthorization authorization, Cancell
12011213
return null;
12021214
}
12031215

1204-
return GetConverter().ConvertToInvariantString(identifier);
1216+
// Optimization: if the key is a string, directly return it as-is.
1217+
if (identifier is string value)
1218+
{
1219+
return value;
1220+
}
1221+
1222+
else
1223+
{
1224+
var converter =
1225+
#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION
1226+
TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey));
1227+
#else
1228+
TypeDescriptor.GetConverter(typeof(TKey));
1229+
#endif
12051230

1206-
[UnconditionalSuppressMessage("Trimming", "IL2026",
1207-
Justification = "Only primitive types are supported as entity keys.")]
1208-
static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey));
1231+
return converter.ConvertToInvariantString(identifier);
1232+
}
12091233
}
12101234
}

0 commit comments

Comments
 (0)