diff --git a/Directory.Build.targets b/Directory.Build.targets index 4ea6948a..25de2311 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -16,11 +16,15 @@ + Condition=" $(RepoRelativeProjectDir.Contains('src')) And + '$(TargetFrameworkIdentifier)' == '.NETCoreApp' And + $([MSBuild]::VersionGreaterThanOrEquals($(TargetFrameworkVersion), '9.0')) "> true @@ -112,6 +116,7 @@ $(DefineConstants);SUPPORTS_CERTIFICATE_LOADER $(DefineConstants);SUPPORTS_JSON_ELEMENT_DEEP_EQUALS $(DefineConstants);SUPPORTS_JSON_ELEMENT_PROPERTY_COUNT + $(DefineConstants);SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION filter)) + if (_provider.GetService(descriptor.FilterTypes[index]) is not IOpenIddictClientHandlerFilter filter) { throw new InvalidOperationException(SR.FormatID0099(descriptor.FilterTypes[index])); } diff --git a/src/OpenIddict.EntityFramework/OpenIddictEntityFrameworkBuilder.cs b/src/OpenIddict.EntityFramework/OpenIddictEntityFrameworkBuilder.cs index 963bc0ab..3daff43a 100644 --- a/src/OpenIddict.EntityFramework/OpenIddictEntityFrameworkBuilder.cs +++ b/src/OpenIddict.EntityFramework/OpenIddictEntityFrameworkBuilder.cs @@ -76,6 +76,15 @@ public sealed class OpenIddictEntityFrameworkBuilder throw new InvalidOperationException(SR.GetResourceString(SR.ID0277)); } +#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION + // If the specified key type isn't a string (which is special-cased by the stores to avoid having to resolve + // a TypeDescriptor instance) and the platform supports type registration, register the key type to ensure the + // TypeDescriptor associated with that type will be preserved by the IL Linker and can be resolved at runtime. + if (typeof(TKey) != typeof(string)) + { + TypeDescriptor.RegisterType(); + } +#endif Services.Replace(ServiceDescriptor.Scoped(static provider => provider.GetRequiredService>())); Services.Replace(ServiceDescriptor.Scoped(static provider => diff --git a/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkApplicationStore.cs b/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkApplicationStore.cs index 0354914f..03a6baee 100644 --- a/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkApplicationStore.cs +++ b/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkApplicationStore.cs @@ -1174,11 +1174,23 @@ public class OpenIddictEntityFrameworkApplicationStore< return default; } - return (TKey?) GetConverter().ConvertFromInvariantString(identifier); + // Optimization: if the key is a string, directly return it as-is. + if (typeof(TKey) == typeof(string)) + { + return (TKey?) (object?) identifier; + } - [UnconditionalSuppressMessage("Trimming", "IL2026", - Justification = "Only primitive types are supported as entity keys.")] - static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey)); + else + { + var converter = +#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION + TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey)); +#else + TypeDescriptor.GetConverter(typeof(TKey)); +#endif + + return (TKey?) converter.ConvertFromInvariantString(identifier); + } } /// @@ -1193,10 +1205,22 @@ public class OpenIddictEntityFrameworkApplicationStore< return null; } - return GetConverter().ConvertToInvariantString(identifier); + // Optimization: if the key is a string, directly return it as-is. + if (identifier is string value) + { + return value; + } - [UnconditionalSuppressMessage("Trimming", "IL2026", - Justification = "Only primitive types are supported as entity keys.")] - static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey)); + else + { + var converter = +#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION + TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey)); +#else + TypeDescriptor.GetConverter(typeof(TKey)); +#endif + + return converter.ConvertToInvariantString(identifier); + } } } diff --git a/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkAuthorizationStore.cs b/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkAuthorizationStore.cs index c20665c0..2aab67fa 100644 --- a/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkAuthorizationStore.cs +++ b/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkAuthorizationStore.cs @@ -975,11 +975,23 @@ public class OpenIddictEntityFrameworkAuthorizationStore< return default; } - return (TKey?) GetConverter().ConvertFromInvariantString(identifier); + // Optimization: if the key is a string, directly return it as-is. + if (typeof(TKey) == typeof(string)) + { + return (TKey?) (object?) identifier; + } + + else + { + var converter = +#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION + TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey)); +#else + TypeDescriptor.GetConverter(typeof(TKey)); +#endif - [UnconditionalSuppressMessage("Trimming", "IL2026", - Justification = "Only primitive types are supported as entity keys.")] - static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey)); + return (TKey?) converter.ConvertFromInvariantString(identifier); + } } /// @@ -994,10 +1006,22 @@ public class OpenIddictEntityFrameworkAuthorizationStore< return null; } - return GetConverter().ConvertToInvariantString(identifier); + // Optimization: if the key is a string, directly return it as-is. + if (identifier is string value) + { + return value; + } + + else + { + var converter = +#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION + TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey)); +#else + TypeDescriptor.GetConverter(typeof(TKey)); +#endif - [UnconditionalSuppressMessage("Trimming", "IL2026", - Justification = "Only primitive types are supported as entity keys.")] - static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey)); + return converter.ConvertToInvariantString(identifier); + } } } diff --git a/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkScopeStore.cs b/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkScopeStore.cs index c93d7e19..67da8668 100644 --- a/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkScopeStore.cs +++ b/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkScopeStore.cs @@ -758,11 +758,23 @@ public class OpenIddictEntityFrameworkScopeStore< return default; } - return (TKey?) GetConverter().ConvertFromInvariantString(identifier); + // Optimization: if the key is a string, directly return it as-is. + if (typeof(TKey) == typeof(string)) + { + return (TKey?) (object?) identifier; + } - [UnconditionalSuppressMessage("Trimming", "IL2026", - Justification = "Only primitive types are supported as entity keys.")] - static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey)); + else + { + var converter = +#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION + TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey)); +#else + TypeDescriptor.GetConverter(typeof(TKey)); +#endif + + return (TKey?) converter.ConvertFromInvariantString(identifier); + } } /// @@ -777,10 +789,22 @@ public class OpenIddictEntityFrameworkScopeStore< return null; } - return GetConverter().ConvertToInvariantString(identifier); + // Optimization: if the key is a string, directly return it as-is. + if (identifier is string value) + { + return value; + } - [UnconditionalSuppressMessage("Trimming", "IL2026", - Justification = "Only primitive types are supported as entity keys.")] - static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey)); + else + { + var converter = +#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION + TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey)); +#else + TypeDescriptor.GetConverter(typeof(TKey)); +#endif + + return converter.ConvertToInvariantString(identifier); + } } } diff --git a/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkTokenStore.cs b/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkTokenStore.cs index c86f9b76..1d33f790 100644 --- a/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkTokenStore.cs +++ b/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkTokenStore.cs @@ -1139,11 +1139,23 @@ public class OpenIddictEntityFrameworkTokenStore< return default; } - return (TKey?) GetConverter().ConvertFromInvariantString(identifier); + // Optimization: if the key is a string, directly return it as-is. + if (typeof(TKey) == typeof(string)) + { + return (TKey?) (object?) identifier; + } + + else + { + var converter = +#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION + TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey)); +#else + TypeDescriptor.GetConverter(typeof(TKey)); +#endif - [UnconditionalSuppressMessage("Trimming", "IL2026", - Justification = "Only primitive types are supported as entity keys.")] - static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey)); + return (TKey?) converter.ConvertFromInvariantString(identifier); + } } /// @@ -1158,10 +1170,22 @@ public class OpenIddictEntityFrameworkTokenStore< return null; } - return GetConverter().ConvertToInvariantString(identifier); + // Optimization: if the key is a string, directly return it as-is. + if (identifier is string value) + { + return value; + } + + else + { + var converter = +#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION + TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey)); +#else + TypeDescriptor.GetConverter(typeof(TKey)); +#endif - [UnconditionalSuppressMessage("Trimming", "IL2026", - Justification = "Only primitive types are supported as entity keys.")] - static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey)); + return converter.ConvertToInvariantString(identifier); + } } } diff --git a/src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreBuilder.cs b/src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreBuilder.cs index 8c3c05f5..1aeb2e61 100644 --- a/src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreBuilder.cs +++ b/src/OpenIddict.EntityFrameworkCore/OpenIddictEntityFrameworkCoreBuilder.cs @@ -89,6 +89,15 @@ public sealed class OpenIddictEntityFrameworkCoreBuilder where TToken : OpenIddictEntityFrameworkCoreToken where TKey : notnull, IEquatable { +#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION + // If the specified key type isn't a string (which is special-cased by the stores to avoid having to resolve + // a TypeDescriptor instance) and the platform supports type registration, register the key type to ensure the + // TypeDescriptor associated with that type will be preserved by the IL Linker and can be resolved at runtime. + if (typeof(TKey) != typeof(string)) + { + TypeDescriptor.RegisterType(); + } +#endif Services.Replace(ServiceDescriptor.Scoped(static provider => provider.GetRequiredService>())); Services.Replace(ServiceDescriptor.Scoped(static provider => diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreApplicationStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreApplicationStore.cs index 14f95a9b..c83a57c0 100644 --- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreApplicationStore.cs +++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreApplicationStore.cs @@ -1255,11 +1255,23 @@ public class OpenIddictEntityFrameworkCoreApplicationStore< return default; } - return (TKey?) GetConverter().ConvertFromInvariantString(identifier); + // Optimization: if the key is a string, directly return it as-is. + if (typeof(TKey) == typeof(string)) + { + return (TKey?) (object?) identifier; + } - [UnconditionalSuppressMessage("Trimming", "IL2026", - Justification = "Only primitive types are supported as entity keys.")] - static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey)); + else + { + var converter = +#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION + TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey)); +#else + TypeDescriptor.GetConverter(typeof(TKey)); +#endif + + return (TKey?) converter.ConvertFromInvariantString(identifier); + } } /// @@ -1274,10 +1286,22 @@ public class OpenIddictEntityFrameworkCoreApplicationStore< return null; } - return GetConverter().ConvertToInvariantString(identifier); + // Optimization: if the key is a string, directly return it as-is. + if (identifier is string value) + { + return value; + } - [UnconditionalSuppressMessage("Trimming", "IL2026", - Justification = "Only primitive types are supported as entity keys.")] - static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey)); + else + { + var converter = +#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION + TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey)); +#else + TypeDescriptor.GetConverter(typeof(TKey)); +#endif + + return converter.ConvertToInvariantString(identifier); + } } } diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreAuthorizationStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreAuthorizationStore.cs index b579bda8..9b6dbf13 100644 --- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreAuthorizationStore.cs +++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreAuthorizationStore.cs @@ -1182,11 +1182,23 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore< return default; } - return (TKey?) GetConverter().ConvertFromInvariantString(identifier); + // Optimization: if the key is a string, directly return it as-is. + if (typeof(TKey) == typeof(string)) + { + return (TKey?) (object?) identifier; + } + + else + { + var converter = +#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION + TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey)); +#else + TypeDescriptor.GetConverter(typeof(TKey)); +#endif - [UnconditionalSuppressMessage("Trimming", "IL2026", - Justification = "Only primitive types are supported as entity keys.")] - static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey)); + return (TKey?) converter.ConvertFromInvariantString(identifier); + } } /// @@ -1201,10 +1213,22 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore< return null; } - return GetConverter().ConvertToInvariantString(identifier); + // Optimization: if the key is a string, directly return it as-is. + if (identifier is string value) + { + return value; + } + + else + { + var converter = +#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION + TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey)); +#else + TypeDescriptor.GetConverter(typeof(TKey)); +#endif - [UnconditionalSuppressMessage("Trimming", "IL2026", - Justification = "Only primitive types are supported as entity keys.")] - static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey)); + return converter.ConvertToInvariantString(identifier); + } } } \ No newline at end of file diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreScopeStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreScopeStore.cs index c2d12419..edc48274 100644 --- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreScopeStore.cs +++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreScopeStore.cs @@ -772,11 +772,23 @@ public class OpenIddictEntityFrameworkCoreScopeStore< return default; } - return (TKey?) GetConverter().ConvertFromInvariantString(identifier); + // Optimization: if the key is a string, directly return it as-is. + if (typeof(TKey) == typeof(string)) + { + return (TKey?) (object?) identifier; + } - [UnconditionalSuppressMessage("Trimming", "IL2026", - Justification = "Only primitive types are supported as entity keys.")] - static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey)); + else + { + var converter = +#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION + TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey)); +#else + TypeDescriptor.GetConverter(typeof(TKey)); +#endif + + return (TKey?) converter.ConvertFromInvariantString(identifier); + } } /// @@ -791,10 +803,22 @@ public class OpenIddictEntityFrameworkCoreScopeStore< return null; } - return GetConverter().ConvertToInvariantString(identifier); + // Optimization: if the key is a string, directly return it as-is. + if (identifier is string value) + { + return value; + } - [UnconditionalSuppressMessage("Trimming", "IL2026", - Justification = "Only primitive types are supported as entity keys.")] - static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey)); + else + { + var converter = +#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION + TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey)); +#else + TypeDescriptor.GetConverter(typeof(TKey)); +#endif + + return converter.ConvertToInvariantString(identifier); + } } } diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreTokenStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreTokenStore.cs index 365fa936..75072617 100644 --- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreTokenStore.cs +++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreTokenStore.cs @@ -1342,11 +1342,23 @@ public class OpenIddictEntityFrameworkCoreTokenStore< return default; } - return (TKey?) GetConverter().ConvertFromInvariantString(identifier); + // Optimization: if the key is a string, directly return it as-is. + if (typeof(TKey) == typeof(string)) + { + return (TKey?) (object?) identifier; + } + + else + { + var converter = +#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION + TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey)); +#else + TypeDescriptor.GetConverter(typeof(TKey)); +#endif - [UnconditionalSuppressMessage("Trimming", "IL2026", - Justification = "Only primitive types are supported as entity keys.")] - static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey)); + return (TKey?) converter.ConvertFromInvariantString(identifier); + } } /// @@ -1361,10 +1373,22 @@ public class OpenIddictEntityFrameworkCoreTokenStore< return null; } - return GetConverter().ConvertToInvariantString(identifier); + // Optimization: if the key is a string, directly return it as-is. + if (identifier is string value) + { + return value; + } + + else + { + var converter = +#if SUPPORTS_TYPE_DESCRIPTOR_TYPE_REGISTRATION + TypeDescriptor.GetConverterFromRegisteredType(typeof(TKey)); +#else + TypeDescriptor.GetConverter(typeof(TKey)); +#endif - [UnconditionalSuppressMessage("Trimming", "IL2026", - Justification = "Only primitive types are supported as entity keys.")] - static TypeConverter GetConverter() => TypeDescriptor.GetConverter(typeof(TKey)); + return converter.ConvertToInvariantString(identifier); + } } } diff --git a/src/OpenIddict.Server/OpenIddictServerDispatcher.cs b/src/OpenIddict.Server/OpenIddictServerDispatcher.cs index 436f6f0f..d3ed305f 100644 --- a/src/OpenIddict.Server/OpenIddictServerDispatcher.cs +++ b/src/OpenIddict.Server/OpenIddictServerDispatcher.cs @@ -121,7 +121,7 @@ public sealed class OpenIddictServerDispatcher : IOpenIddictServerDispatcher { for (var index = 0; index < descriptor.FilterTypes.Length; index++) { - if (!(_provider.GetService(descriptor.FilterTypes[index]) is IOpenIddictServerHandlerFilter filter)) + if (_provider.GetService(descriptor.FilterTypes[index]) is not IOpenIddictServerHandlerFilter filter) { throw new InvalidOperationException(SR.FormatID0099(descriptor.FilterTypes[index])); } diff --git a/src/OpenIddict.Validation/OpenIddictValidationDispatcher.cs b/src/OpenIddict.Validation/OpenIddictValidationDispatcher.cs index e5fa2366..f7193a15 100644 --- a/src/OpenIddict.Validation/OpenIddictValidationDispatcher.cs +++ b/src/OpenIddict.Validation/OpenIddictValidationDispatcher.cs @@ -121,7 +121,7 @@ public sealed class OpenIddictValidationDispatcher : IOpenIddictValidationDispat { for (var index = 0; index < descriptor.FilterTypes.Length; index++) { - if (!(_provider.GetService(descriptor.FilterTypes[index]) is IOpenIddictValidationHandlerFilter filter)) + if (_provider.GetService(descriptor.FilterTypes[index]) is not IOpenIddictValidationHandlerFilter filter) { throw new InvalidOperationException(SR.FormatID0099(descriptor.FilterTypes[index])); }