diff --git a/build/assets.msbuildproj b/build/assets.msbuildproj index 8d3dba2a..0ae99dc5 100644 --- a/build/assets.msbuildproj +++ b/build/assets.msbuildproj @@ -2,6 +2,7 @@ netstandard1.0 false + $(NoWarn);NETSDK1215 diff --git a/src/Abstractions/src/Asp.Versioning.Abstractions/Asp.Versioning.Abstractions.csproj b/src/Abstractions/src/Asp.Versioning.Abstractions/Asp.Versioning.Abstractions.csproj index 68dd7991..861b642c 100644 --- a/src/Abstractions/src/Asp.Versioning.Abstractions/Asp.Versioning.Abstractions.csproj +++ b/src/Abstractions/src/Asp.Versioning.Abstractions/Asp.Versioning.Abstractions.csproj @@ -14,6 +14,10 @@ true + + false + + diff --git a/src/AspNetCore/OData/src/Asp.Versioning.OData.ApiExplorer/ApiExplorer/PartialODataDescriptionProvider.cs b/src/AspNetCore/OData/src/Asp.Versioning.OData.ApiExplorer/ApiExplorer/PartialODataDescriptionProvider.cs index 47eac901..4099958b 100644 --- a/src/AspNetCore/OData/src/Asp.Versioning.OData.ApiExplorer/ApiExplorer/PartialODataDescriptionProvider.cs +++ b/src/AspNetCore/OData/src/Asp.Versioning.OData.ApiExplorer/ApiExplorer/PartialODataDescriptionProvider.cs @@ -201,6 +201,8 @@ public ModelMetadata GetMetadataForType( Type modelType ) => throw new NotImplementedException(); } + [UnconditionalSuppressMessage( "ILLink", "IL2092" )] + [UnconditionalSuppressMessage( "ILLink", "IL2093" )] private sealed class StubModelTypeBuilder : IModelTypeBuilder { public Type NewActionParameters( IEdmModel model, IEdmAction action, string controllerName, ApiVersion apiVersion ) => diff --git a/src/AspNetCore/OData/src/Asp.Versioning.OData.ApiExplorer/Asp.Versioning.OData.ApiExplorer.csproj b/src/AspNetCore/OData/src/Asp.Versioning.OData.ApiExplorer/Asp.Versioning.OData.ApiExplorer.csproj index a443fa16..bf0661c6 100644 --- a/src/AspNetCore/OData/src/Asp.Versioning.OData.ApiExplorer/Asp.Versioning.OData.ApiExplorer.csproj +++ b/src/AspNetCore/OData/src/Asp.Versioning.OData.ApiExplorer/Asp.Versioning.OData.ApiExplorer.csproj @@ -8,6 +8,7 @@ ASP.NET Core API Versioning API Explorer for OData v4.0 The API Explorer extensions for ASP.NET Core API Versioning and OData v4.0. Asp;AspNet;AspNetCore;Versioning;ApiExplorer;OData + true diff --git a/src/AspNetCore/OData/src/Asp.Versioning.OData/Asp.Versioning.OData.csproj b/src/AspNetCore/OData/src/Asp.Versioning.OData/Asp.Versioning.OData.csproj index e69c80d7..64df816f 100644 --- a/src/AspNetCore/OData/src/Asp.Versioning.OData/Asp.Versioning.OData.csproj +++ b/src/AspNetCore/OData/src/Asp.Versioning.OData/Asp.Versioning.OData.csproj @@ -8,6 +8,7 @@ ASP.NET Core API Versioning with OData v4.0 A service API versioning library for Microsoft ASP.NET Core with OData v4.0. Asp;AspNet;AspNetCore;Versioning;OData + true diff --git a/src/AspNetCore/OData/src/Asp.Versioning.OData/DependencyInjection/IServiceCollectionExtensions.cs b/src/AspNetCore/OData/src/Asp.Versioning.OData/DependencyInjection/IServiceCollectionExtensions.cs index 16432665..0f17e2eb 100644 --- a/src/AspNetCore/OData/src/Asp.Versioning.OData/DependencyInjection/IServiceCollectionExtensions.cs +++ b/src/AspNetCore/OData/src/Asp.Versioning.OData/DependencyInjection/IServiceCollectionExtensions.cs @@ -31,6 +31,7 @@ internal static ApplicationPartManager GetOrCreateApplicationPartManager( this I return partManager; } + [UnconditionalSuppressMessage( "ILLink", "IL2072", Justification = "Model configuration types are never trimmed" )] internal static void AddModelConfigurationsAsServices( this IServiceCollection services, ApplicationPartManager partManager ) { var feature = new ModelConfigurationFeature(); diff --git a/src/AspNetCore/OData/src/Asp.Versioning.OData/OData/ODataMultiModelApplicationModelProvider.cs b/src/AspNetCore/OData/src/Asp.Versioning.OData/OData/ODataMultiModelApplicationModelProvider.cs index cc798280..5676e28f 100644 --- a/src/AspNetCore/OData/src/Asp.Versioning.OData/OData/ODataMultiModelApplicationModelProvider.cs +++ b/src/AspNetCore/OData/src/Asp.Versioning.OData/OData/ODataMultiModelApplicationModelProvider.cs @@ -135,7 +135,8 @@ private static Type GetDefaultApplicationModelProviderType() return Type.GetType( $"{TypeName}, {assemblyName}", throwOnError: true, ignoreCase: false )!; } - private static Func, IApplicationModelProvider> CreateActivator( Type type ) + private static Func, IApplicationModelProvider> CreateActivator( + [DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicConstructors )] Type type ) { var options = Parameter( typeof( IOptions ), "options" ); var @new = New( type.GetConstructors()[0], options ); diff --git a/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc.ApiExplorer/ApiExplorerOptionsFactory{T}.cs b/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc.ApiExplorer/ApiExplorerOptionsFactory{T}.cs index 1a79e0a3..6c94a430 100644 --- a/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc.ApiExplorer/ApiExplorerOptionsFactory{T}.cs +++ b/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc.ApiExplorer/ApiExplorerOptionsFactory{T}.cs @@ -3,13 +3,15 @@ namespace Asp.Versioning.ApiExplorer; using Microsoft.Extensions.Options; +using static System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes; /// /// Represents a factory to create API explorer options. /// /// The type of options to create. [CLSCompliant( false )] -public class ApiExplorerOptionsFactory : OptionsFactory where T : ApiExplorerOptions +public class ApiExplorerOptionsFactory<[DynamicallyAccessedMembers( PublicParameterlessConstructor )] T> + : OptionsFactory where T : ApiExplorerOptions { private readonly IOptions optionsHolder; diff --git a/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc.ApiExplorer/Asp.Versioning.Mvc.ApiExplorer.csproj b/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc.ApiExplorer/Asp.Versioning.Mvc.ApiExplorer.csproj index 528a203a..5845752b 100644 --- a/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc.ApiExplorer/Asp.Versioning.Mvc.ApiExplorer.csproj +++ b/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc.ApiExplorer/Asp.Versioning.Mvc.ApiExplorer.csproj @@ -8,6 +8,7 @@ ASP.NET Core API Versioning API Explorer The API Explorer extensions for ASP.NET Core API Versioning. Asp;AspNet;AspNetCore;Versioning;ApiExplorer + true diff --git a/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc/Asp.Versioning.Mvc.csproj b/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc/Asp.Versioning.Mvc.csproj index 52963338..21ca9fe8 100644 --- a/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc/Asp.Versioning.Mvc.csproj +++ b/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc/Asp.Versioning.Mvc.csproj @@ -9,6 +9,7 @@ A service API versioning library for Microsoft ASP.NET Core MVC. Asp;AspNet;AspNetCore;MVC;Versioning true + true diff --git a/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc/DependencyInjection/IApiVersioningBuilderExtensions.cs b/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc/DependencyInjection/IApiVersioningBuilderExtensions.cs index eef6b507..21e66163 100644 --- a/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc/DependencyInjection/IApiVersioningBuilderExtensions.cs +++ b/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc/DependencyInjection/IApiVersioningBuilderExtensions.cs @@ -16,6 +16,7 @@ namespace Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using System.Runtime.CompilerServices; using static ServiceDescriptor; +using static System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes; /// /// Provides ASP.NET Core MVC specific extension methods for . @@ -85,7 +86,11 @@ private static object CreateInstance( this IServiceProvider services, ServiceDes return ActivatorUtilities.GetServiceOrCreateInstance( services, descriptor.ImplementationType! ); } - private static void TryReplace( this IServiceCollection services ) + private static void TryReplace< + TService, + TImplementation, + [DynamicallyAccessedMembers( NonPublicConstructors | PublicConstructors )] + TReplacement>( this IServiceCollection services ) { var serviceType = typeof( TService ); var implementationType = typeof( TImplementation ); diff --git a/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc/Routing/ApiVersionUrlHelper.cs b/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc/Routing/ApiVersionUrlHelper.cs index bbf03793..bd3e398e 100644 --- a/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc/Routing/ApiVersionUrlHelper.cs +++ b/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc/Routing/ApiVersionUrlHelper.cs @@ -98,9 +98,30 @@ public ApiVersionUrlHelper( ActionContext actionContext, IUrlHelper url ) return current; } - if ( current is not RouteValueDictionary values ) + RouteValueDictionary values; + + if ( current is null ) + { + values = new() { { key, value } }; + return values; + } + + if ( current is RouteValueDictionary dictionary ) + { + values = dictionary; + } + else if ( current is IEnumerable> kvps ) { - values = current == null ? new() : new( current ); + values = []; + + foreach ( var kvp in kvps ) + { + values.Add( kvp.Key, kvp.Value ); + } + } + else + { + return current; } if ( !values.ContainsKey( key ) ) diff --git a/src/Client/src/Asp.Versioning.Http.Client/Asp.Versioning.Http.Client.csproj b/src/Client/src/Asp.Versioning.Http.Client/Asp.Versioning.Http.Client.csproj index b704593d..08fc140f 100644 --- a/src/Client/src/Asp.Versioning.Http.Client/Asp.Versioning.Http.Client.csproj +++ b/src/Client/src/Asp.Versioning.Http.Client/Asp.Versioning.Http.Client.csproj @@ -14,6 +14,10 @@ true + + false + + diff --git a/src/Common/src/Common.Backport/Common.Backport.msbuildproj b/src/Common/src/Common.Backport/Common.Backport.msbuildproj index 9dd66e3a..0da069a9 100644 --- a/src/Common/src/Common.Backport/Common.Backport.msbuildproj +++ b/src/Common/src/Common.Backport/Common.Backport.msbuildproj @@ -1,6 +1,7 @@ netstandard1.0 + $(NoWarn);NETSDK1215 diff --git a/src/Common/src/Common.Mvc/Conventions/ActionConventionBuilderExtensions.cs b/src/Common/src/Common.Mvc/Conventions/ActionConventionBuilderExtensions.cs index 98cb8aa3..63464548 100644 --- a/src/Common/src/Common.Mvc/Conventions/ActionConventionBuilderExtensions.cs +++ b/src/Common/src/Common.Mvc/Conventions/ActionConventionBuilderExtensions.cs @@ -73,6 +73,9 @@ public static IActionConventionBuilder Action /// If there is only one corresponding match found, then the argument types are ignored; /// otherwise, the argument types are used for method overload resolution. Action /// methods that have the applied will also be ignored. +#if !NETFRAMEWORK + [UnconditionalSuppressMessage( "ILLink", "IL2072", Justification = "Controller types are never trimmed" )] +#endif public static IActionConventionBuilder Action( this IActionConventionBuilder builder, string methodName, params Type[] argumentTypes ) { ArgumentNullException.ThrowIfNull( builder ); diff --git a/src/Common/src/Common.Mvc/Conventions/ActionMethodResolver.cs b/src/Common/src/Common.Mvc/Conventions/ActionMethodResolver.cs index 3c0fa420..8feb6bfd 100644 --- a/src/Common/src/Common.Mvc/Conventions/ActionMethodResolver.cs +++ b/src/Common/src/Common.Mvc/Conventions/ActionMethodResolver.cs @@ -10,12 +10,19 @@ namespace Asp.Versioning.Conventions; #if NETFRAMEWORK using System.Web.Http; #endif +using static System.Reflection.BindingFlags; internal static class ActionMethodResolver { - internal static MethodInfo Resolve( Type controllerType, string methodName, Type[] argumentTypes ) + internal static MethodInfo Resolve( +#if !NETFRAMEWORK + [DynamicallyAccessedMembers( DynamicallyAccessedMemberTypes.PublicMethods )] +#endif + Type controllerType, + string methodName, + Type[] argumentTypes ) { - var methods = controllerType.GetRuntimeMethods().Where( m => m.Name == methodName && IsAction( m ) ).ToArray(); + var methods = controllerType.GetMethods( Instance | Public ).Where( m => m.Name == methodName && IsAction( m ) ).ToArray(); switch ( methods.Length ) { diff --git a/src/Common/src/Common.Mvc/Conventions/ControllerConventionBuilderExtensions.cs b/src/Common/src/Common.Mvc/Conventions/ControllerConventionBuilderExtensions.cs index 328b8b70..47e7a491 100644 --- a/src/Common/src/Common.Mvc/Conventions/ControllerConventionBuilderExtensions.cs +++ b/src/Common/src/Common.Mvc/Conventions/ControllerConventionBuilderExtensions.cs @@ -73,6 +73,9 @@ public static IActionConventionBuilder Action /// If there is only one corresponding match found, then the argument types are ignored; /// otherwise, the argument types are used for method overload resolution. Action /// methods that have the applied will also be ignored. +#if !NETFRAMEWORK + [UnconditionalSuppressMessage( "ILLink", "IL2072", Justification = "Controller types are never trimmed" )] +#endif public static IActionConventionBuilder Action( this IControllerConventionBuilder builder, string methodName, params Type[] argumentTypes ) { ArgumentNullException.ThrowIfNull( builder ); diff --git a/src/Common/src/Common.OData.ApiExplorer/Conventions/ODataActionQueryOptionsConventionBuilderExtensions.cs b/src/Common/src/Common.OData.ApiExplorer/Conventions/ODataActionQueryOptionsConventionBuilderExtensions.cs index bcd941a0..33ab2471 100644 --- a/src/Common/src/Common.OData.ApiExplorer/Conventions/ODataActionQueryOptionsConventionBuilderExtensions.cs +++ b/src/Common/src/Common.OData.ApiExplorer/Conventions/ODataActionQueryOptionsConventionBuilderExtensions.cs @@ -16,6 +16,7 @@ namespace Asp.Versioning.Conventions; using System.Web.Http; using System.Web.Http.Controllers; #endif +using static System.Reflection.BindingFlags; /// /// Provides extension methods for the @@ -187,6 +188,9 @@ public static ODataActionQueryOptionsConventionBuilder Actionargument types are ignored; /// otherwise, the argument types are used for method overload resolution. Action /// methods that have the applied will also be ignored. +#if !NETFRAMEWORK + [UnconditionalSuppressMessage( "ILLink", "IL2075", Justification = "Controller types and actions are never trimmed" )] +#endif public static ODataActionQueryOptionsConventionBuilder Action( this IODataActionQueryOptionsConventionBuilder builder, string methodName, @@ -197,7 +201,7 @@ public static ODataActionQueryOptionsConventionBuilder Action( string message; var methods = builder.ControllerType - .GetRuntimeMethods() + .GetMethods( Instance | Public ) .Where( m => m.Name == methodName && IsAction( m ) ) .ToArray(); diff --git a/src/Common/src/Common.OData.ApiExplorer/Microsoft.OData.Edm/EdmExtensions.cs b/src/Common/src/Common.OData.ApiExplorer/Microsoft.OData.Edm/EdmExtensions.cs index 16ef9c9c..f9c60670 100644 --- a/src/Common/src/Common.OData.ApiExplorer/Microsoft.OData.Edm/EdmExtensions.cs +++ b/src/Common/src/Common.OData.ApiExplorer/Microsoft.OData.Edm/EdmExtensions.cs @@ -37,6 +37,9 @@ internal static class EdmExtensions return null; } +#if !NETFRAMEWORK + [UnconditionalSuppressMessage( "ILLink", "IL2057", Justification = "The types being referenced are well-known and will not be trimmed." )] +#endif private static Type? DeriveFromWellKnowPrimitive( string edmFullName ) => edmFullName switch { "Edm.String" or "Edm.Byte" or "Edm.SByte" or "Edm.Int16" or "Edm.Int32" or "Edm.Int64" or diff --git a/src/Common/src/Common.OData.ApiExplorer/OData/ClassProperty.cs b/src/Common/src/Common.OData.ApiExplorer/OData/ClassProperty.cs index 98784a2f..f5959f92 100644 --- a/src/Common/src/Common.OData.ApiExplorer/OData/ClassProperty.cs +++ b/src/Common/src/Common.OData.ApiExplorer/OData/ClassProperty.cs @@ -21,6 +21,9 @@ internal ClassProperty( PropertyInfo clrProperty, Type propertyType ) Attributes = clrProperty.DeclaredAttributes().ToArray(); } +#if !NETFRAMEWORK + [UnconditionalSuppressMessage( "ILLink", "IL2072" )] +#endif internal ClassProperty( IEdmOperationParameter parameter, TypeSubstitutionContext context ) { Name = parameter.Name; diff --git a/src/Common/src/Common.OData.ApiExplorer/OData/DefaultModelTypeBuilder.cs b/src/Common/src/Common.OData.ApiExplorer/OData/DefaultModelTypeBuilder.cs index f8a836ec..76fec0ff 100644 --- a/src/Common/src/Common.OData.ApiExplorer/OData/DefaultModelTypeBuilder.cs +++ b/src/Common/src/Common.OData.ApiExplorer/OData/DefaultModelTypeBuilder.cs @@ -14,6 +14,9 @@ namespace Asp.Versioning.OData; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Text; +#if !NETFRAMEWORK +using static System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes; +#endif using static System.Globalization.CultureInfo; using static System.Guid; using static System.Reflection.BindingFlags; @@ -22,6 +25,11 @@ namespace Asp.Versioning.OData; /// /// Represents the default model type builder. /// +#if !NETFRAMEWORK +[UnconditionalSuppressMessage( "ILLink", "IL2055")] +[UnconditionalSuppressMessage( "ILLink", "IL2070")] +[UnconditionalSuppressMessage( "ILLink", "IL2073")] +#endif public sealed class DefaultModelTypeBuilder : IModelTypeBuilder { /* design: there is typically a 1:1 relationship between an edm and api version. odata model bound settings @@ -59,7 +67,17 @@ private DefaultModelTypeBuilder( bool excludeAdHocModels, bool adHoc ) public DefaultModelTypeBuilder( bool includeAdHocModels = false ) => excludeAdHocModels = !includeAdHocModels; /// - public Type NewStructuredType( IEdmModel model, IEdmStructuredType structuredType, Type clrType, ApiVersion apiVersion ) +#if !NETFRAMEWORK + [return: DynamicallyAccessedMembers( Interfaces | PublicProperties )] +#endif + public Type NewStructuredType( + IEdmModel model, + IEdmStructuredType structuredType, +#if !NETFRAMEWORK + [DynamicallyAccessedMembers( Interfaces | PublicProperties )] +#endif + Type clrType, + ApiVersion apiVersion ) { ArgumentNullException.ThrowIfNull( model ); @@ -88,6 +106,9 @@ public Type NewStructuredType( IEdmModel model, IEdmStructuredType structuredTyp } /// +#if !NETFRAMEWORK + [return: DynamicallyAccessedMembers( Interfaces | PublicProperties )] +#endif public Type NewActionParameters( IEdmModel model, IEdmAction action, string controllerName, ApiVersion apiVersion ) { ArgumentNullException.ThrowIfNull( model ); @@ -417,10 +438,6 @@ private static PropertyBuilder AddProperty( var field = addTo.DefineField( "_" + name, shouldBeAdded, FieldAttributes.Private ); var propertyBuilder = addTo.DefineProperty( name, PropertyAttributes.HasDefault, shouldBeAdded, null ); var getter = addTo.DefineMethod( "get_" + name, propertyMethodAttributes, shouldBeAdded, Type.EmptyTypes ); - - /* returnType is 'null' instead of type(void) as per docs - * see: https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.propertybuilder?view=net-9.0 - */ var setter = addTo.DefineMethod( "set_" + name, propertyMethodAttributes, null, [shouldBeAdded] ); var il = getter.GetILGenerator(); diff --git a/src/Common/src/Common.OData.ApiExplorer/OData/IModelTypeBuilder.cs b/src/Common/src/Common.OData.ApiExplorer/OData/IModelTypeBuilder.cs index 96b80e9f..cfc73a43 100644 --- a/src/Common/src/Common.OData.ApiExplorer/OData/IModelTypeBuilder.cs +++ b/src/Common/src/Common.OData.ApiExplorer/OData/IModelTypeBuilder.cs @@ -8,6 +8,9 @@ namespace Asp.Versioning.OData; using Microsoft.AspNetCore.OData.Formatter; #endif using Microsoft.OData.Edm; +#if !NETFRAMEWORK +using static System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes; +#endif /// /// Defines the behavior of a model type builder. @@ -26,7 +29,17 @@ public interface IModelTypeBuilder /// structured type. /// If a substitution is not required, the original CLR type is returned. When a substitution /// type is generated, it is performed only once per API version. - Type NewStructuredType( IEdmModel model, IEdmStructuredType structuredType, Type clrType, ApiVersion apiVersion ); +#if !NETFRAMEWORK + [return: DynamicallyAccessedMembers( Interfaces | PublicProperties )] +#endif + Type NewStructuredType( + IEdmModel model, + IEdmStructuredType structuredType, +#if !NETFRAMEWORK + [DynamicallyAccessedMembers( Interfaces | PublicProperties )] +#endif + Type clrType, + ApiVersion apiVersion ); /// /// Creates an returns a strongly-typed definition for OData action parameters. @@ -39,5 +52,8 @@ public interface IModelTypeBuilder /// OData action parameters are modeled as a dictionary, /// which is difficult to use effectively by documentation tools such as the API Explorer. The corresponding type is generated only once per /// API version. +#if !NETFRAMEWORK + [return: DynamicallyAccessedMembers( Interfaces | PublicProperties )] +#endif Type NewActionParameters( IEdmModel model, IEdmAction action, string controllerName, ApiVersion apiVersion ); } \ No newline at end of file diff --git a/src/Common/src/Common.OData.ApiExplorer/OData/TypeExtensions.cs b/src/Common/src/Common.OData.ApiExplorer/OData/TypeExtensions.cs index a32cd16a..72c76457 100644 --- a/src/Common/src/Common.OData.ApiExplorer/OData/TypeExtensions.cs +++ b/src/Common/src/Common.OData.ApiExplorer/OData/TypeExtensions.cs @@ -16,6 +16,8 @@ namespace Asp.Versioning.OData; using System.Runtime.CompilerServices; #if NETFRAMEWORK using IActionResult = System.Web.Http.IHttpActionResult; +#else +using static System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes; #endif /// @@ -41,7 +43,17 @@ public static partial class TypeExtensions /// The current type substitution context. /// The original or a substitution type based on the /// provided . - public static Type SubstituteIfNecessary( this Type type, TypeSubstitutionContext context ) +#if !NETFRAMEWORK + [UnconditionalSuppressMessage( "ILLink", "IL2026" )] + [UnconditionalSuppressMessage( "ILLink", "IL2073" )] + [return: DynamicallyAccessedMembers( Interfaces | PublicProperties )] +#endif + public static Type SubstituteIfNecessary( +#if !NETFRAMEWORK + [DynamicallyAccessedMembers( Interfaces | PublicProperties )] +#endif + this Type type, + TypeSubstitutionContext context ) { ArgumentNullException.ThrowIfNull( type ); ArgumentNullException.ThrowIfNull( context ); @@ -151,7 +163,13 @@ internal static Type ExtractInnerType( this Type type ) return type; } - private static bool IsSubstitutableGeneric( Type type, Stack openTypes, out Type? innerType ) + private static bool IsSubstitutableGeneric( +#if !NETFRAMEWORK + [DynamicallyAccessedMembers( Interfaces )] +#endif + Type type, + Stack openTypes, + out Type? innerType ) { innerType = default; @@ -212,6 +230,10 @@ private static bool IsSubstitutableGeneric( Type type, Stack openTypes, ou return true; } +#if !NETFRAMEWORK + [RequiresDynamicCode( "Might not be available at runtime" )] + [RequiresUnreferencedCode( "Cannot be validated by trim analysis" )] +#endif private static Type CloseGeneric( Stack openTypes, Type innerType ) { var type = openTypes.Pop(); @@ -241,7 +263,10 @@ private static bool CanBeSubstituted( Type type ) => #endif !type.IsODataActionParameters(); - internal static bool IsEnumerable( this Type type, [NotNullWhen( true )] out Type? itemType ) +#if !NETFRAMEWORK + [UnconditionalSuppressMessage( "ILLink", "IL2070" )] +#endif + internal static bool IsEnumerable(this Type type, [NotNullWhen( true )] out Type? itemType ) { var types = new Queue(); diff --git a/src/Common/test/Common.OData.ApiExplorer.Tests/OData/DefaultModelTypeBuilderTest.cs b/src/Common/test/Common.OData.ApiExplorer.Tests/OData/DefaultModelTypeBuilderTest.cs index 2a0fc160..d5295031 100644 --- a/src/Common/test/Common.OData.ApiExplorer.Tests/OData/DefaultModelTypeBuilderTest.cs +++ b/src/Common/test/Common.OData.ApiExplorer.Tests/OData/DefaultModelTypeBuilderTest.cs @@ -410,16 +410,16 @@ public void substitute_should_resolve_types_that_reference_a_model_that_match_th } [Fact] - public void substituted_type_should_have_valid_runtime_properties__issue1104() + public void ignoring_property_should_force_substitution_with_valid_runtime_properties() { // arrange var modelBuilder = new ODataConventionModelBuilder(); - var address = modelBuilder.EntitySet
( nameof( Address ) ).EntityType; - address.Ignore( x => x.City ); // force substitution - var addressType = typeof( Address ); + + address.Ignore( x => x.City ); var context = NewContext( modelBuilder.GetEdmModel() ); + var addressType = typeof( Address ); // act var substitutedType = addressType.SubstituteIfNecessary( context ); @@ -428,6 +428,7 @@ public void substituted_type_should_have_valid_runtime_properties__issue1104() substitutedType.Should().NotBe( addressType ); #if NET452 substitutedType.GetRuntimeProperties().Should().HaveCount( 5 ); + foreach ( var substitutedProperty in substitutedType.GetRuntimeProperties() ) { substitutedProperty.Should().NotBeNull();