From c125308e2d161ae1df475843c51d2d1cacc576fb Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Mon, 3 Aug 2020 15:56:21 -0500 Subject: [PATCH 1/2] Annotate Extensions.Options to make it linker friendly Fix #40236 --- .../Microsoft.Extensions.Options.sln | 14 ++-- .../ref/Microsoft.Extensions.Options.cs | 28 +++---- .../ref/Microsoft.Extensions.Options.csproj | 2 + .../src/IOptions.cs | 5 +- .../src/IOptionsFactory.cs | 5 +- .../src/IOptionsMonitor.cs | 3 +- .../src/IOptionsMonitorCache.cs | 4 +- .../src/IOptionsSnapshot.cs | 6 +- .../src/Microsoft.Extensions.Options.csproj | 5 ++ .../src/Options.cs | 8 +- .../src/OptionsCache.cs | 5 +- .../src/OptionsFactory.cs | 5 +- .../src/OptionsManager.cs | 7 +- .../src/OptionsMonitor.cs | 6 +- .../src/OptionsMonitorExtensions.cs | 7 +- .../src/OptionsServiceCollectionExtensions.cs | 11 ++- .../src/OptionsWrapper.cs | 6 +- .../ComplexOptions.cs | 0 .../FakeChangeToken.cs | 0 .../FakeOptions.cs | 0 .../FakeOptionsFactory.cs | 0 .../Microsoft.Extensions.Options.Tests.csproj | 0 .../OptionsBuilderTest.cs | 0 .../OptionsFactoryTests.cs | 0 .../OptionsMonitorTest.cs | 0 .../OptionsSnapshotTest.cs | 0 .../OptionsTest.cs | 0 .../OptionsValidationTests.cs | 0 .../tests/TrimmingTests/ConfigureTests.cs | 78 +++++++++++++++++++ ...soft.Extensions.Options.TrimmingTests.proj | 16 ++++ 30 files changed, 183 insertions(+), 38 deletions(-) rename src/libraries/Microsoft.Extensions.Options/tests/{ => Microsoft.Extensions.Options.Tests}/ComplexOptions.cs (100%) rename src/libraries/Microsoft.Extensions.Options/tests/{ => Microsoft.Extensions.Options.Tests}/FakeChangeToken.cs (100%) rename src/libraries/Microsoft.Extensions.Options/tests/{ => Microsoft.Extensions.Options.Tests}/FakeOptions.cs (100%) rename src/libraries/Microsoft.Extensions.Options/tests/{ => Microsoft.Extensions.Options.Tests}/FakeOptionsFactory.cs (100%) rename src/libraries/Microsoft.Extensions.Options/tests/{ => Microsoft.Extensions.Options.Tests}/Microsoft.Extensions.Options.Tests.csproj (100%) rename src/libraries/Microsoft.Extensions.Options/tests/{ => Microsoft.Extensions.Options.Tests}/OptionsBuilderTest.cs (100%) rename src/libraries/Microsoft.Extensions.Options/tests/{ => Microsoft.Extensions.Options.Tests}/OptionsFactoryTests.cs (100%) rename src/libraries/Microsoft.Extensions.Options/tests/{ => Microsoft.Extensions.Options.Tests}/OptionsMonitorTest.cs (100%) rename src/libraries/Microsoft.Extensions.Options/tests/{ => Microsoft.Extensions.Options.Tests}/OptionsSnapshotTest.cs (100%) rename src/libraries/Microsoft.Extensions.Options/tests/{ => Microsoft.Extensions.Options.Tests}/OptionsTest.cs (100%) rename src/libraries/Microsoft.Extensions.Options/tests/{ => Microsoft.Extensions.Options.Tests}/OptionsValidationTests.cs (100%) create mode 100644 src/libraries/Microsoft.Extensions.Options/tests/TrimmingTests/ConfigureTests.cs create mode 100644 src/libraries/Microsoft.Extensions.Options/tests/TrimmingTests/Microsoft.Extensions.Options.TrimmingTests.proj diff --git a/src/libraries/Microsoft.Extensions.Options/Microsoft.Extensions.Options.sln b/src/libraries/Microsoft.Extensions.Options/Microsoft.Extensions.Options.sln index b67b0a590f1f1..569f822cf139d 100644 --- a/src/libraries/Microsoft.Extensions.Options/Microsoft.Extensions.Options.sln +++ b/src/libraries/Microsoft.Extensions.Options/Microsoft.Extensions.Options.sln @@ -13,9 +13,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Option EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Options", "src\Microsoft.Extensions.Options.csproj", "{0ACF563C-7E53-469A-A61D-B93916DED810}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Options.Tests", "tests\Microsoft.Extensions.Options.Tests.csproj", "{77771F73-3122-49BD-85D8-6D880B9902F3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{A5C2304B-0A92-427A-BD01-C7927EFA8B78}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{A5C2304B-0A92-427A-BD01-C7927EFA8B78}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Options.Tests", "tests\Microsoft.Extensions.Options.Tests\Microsoft.Extensions.Options.Tests.csproj", "{0905577D-D2A0-4EF1-848B-8A99F12BE3D0}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -31,14 +31,14 @@ Global {0ACF563C-7E53-469A-A61D-B93916DED810}.Debug|Any CPU.Build.0 = Debug|Any CPU {0ACF563C-7E53-469A-A61D-B93916DED810}.Release|Any CPU.ActiveCfg = Release|Any CPU {0ACF563C-7E53-469A-A61D-B93916DED810}.Release|Any CPU.Build.0 = Release|Any CPU - {77771F73-3122-49BD-85D8-6D880B9902F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {77771F73-3122-49BD-85D8-6D880B9902F3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {77771F73-3122-49BD-85D8-6D880B9902F3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {77771F73-3122-49BD-85D8-6D880B9902F3}.Release|Any CPU.Build.0 = Release|Any CPU {A5C2304B-0A92-427A-BD01-C7927EFA8B78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A5C2304B-0A92-427A-BD01-C7927EFA8B78}.Debug|Any CPU.Build.0 = Debug|Any CPU {A5C2304B-0A92-427A-BD01-C7927EFA8B78}.Release|Any CPU.ActiveCfg = Release|Any CPU {A5C2304B-0A92-427A-BD01-C7927EFA8B78}.Release|Any CPU.Build.0 = Release|Any CPU + {0905577D-D2A0-4EF1-848B-8A99F12BE3D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0905577D-D2A0-4EF1-848B-8A99F12BE3D0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0905577D-D2A0-4EF1-848B-8A99F12BE3D0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0905577D-D2A0-4EF1-848B-8A99F12BE3D0}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -46,8 +46,8 @@ Global GlobalSection(NestedProjects) = preSolution {9F96CC5A-969C-47FA-81DB-7093598A226F} = {5827CC1E-1A61-4799-96B4-AB1052346A52} {0ACF563C-7E53-469A-A61D-B93916DED810} = {9205B11D-A45B-4F2C-BF37-8C5F26FCBDB7} - {77771F73-3122-49BD-85D8-6D880B9902F3} = {CAB34510-96B9-422E-904F-C03476004E13} {A5C2304B-0A92-427A-BD01-C7927EFA8B78} = {CAB34510-96B9-422E-904F-C03476004E13} + {0905577D-D2A0-4EF1-848B-8A99F12BE3D0} = {CAB34510-96B9-422E-904F-C03476004E13} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5DE09ECD-4E45-4B08-B44A-327EF5203D1B} diff --git a/src/libraries/Microsoft.Extensions.Options/ref/Microsoft.Extensions.Options.cs b/src/libraries/Microsoft.Extensions.Options/ref/Microsoft.Extensions.Options.cs index 32f254eff792e..d0b8af0aec10d 100644 --- a/src/libraries/Microsoft.Extensions.Options/ref/Microsoft.Extensions.Options.cs +++ b/src/libraries/Microsoft.Extensions.Options/ref/Microsoft.Extensions.Options.cs @@ -13,8 +13,8 @@ public static partial class OptionsServiceCollectionExtensions public static Microsoft.Extensions.Options.OptionsBuilder AddOptions(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name) where TOptions : class { throw null; } public static Microsoft.Extensions.DependencyInjection.IServiceCollection ConfigureAll(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action configureOptions) where TOptions : class { throw null; } public static Microsoft.Extensions.DependencyInjection.IServiceCollection ConfigureOptions(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, object configureInstance) { throw null; } - public static Microsoft.Extensions.DependencyInjection.IServiceCollection ConfigureOptions(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Type configureType) { throw null; } - public static Microsoft.Extensions.DependencyInjection.IServiceCollection ConfigureOptions(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) where TConfigureOptions : class { throw null; } + public static Microsoft.Extensions.DependencyInjection.IServiceCollection ConfigureOptions(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicConstructors)] System.Type configureType) { throw null; } + public static Microsoft.Extensions.DependencyInjection.IServiceCollection ConfigureOptions<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] TConfigureOptions>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services) where TConfigureOptions : class { throw null; } public static Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action configureOptions) where TOptions : class { throw null; } public static Microsoft.Extensions.DependencyInjection.IServiceCollection Configure(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, string name, System.Action configureOptions) where TOptions : class { throw null; } public static Microsoft.Extensions.DependencyInjection.IServiceCollection PostConfigureAll(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, System.Action configureOptions) where TOptions : class { throw null; } @@ -106,28 +106,28 @@ public partial interface IOptionsChangeTokenSource string Name { get; } Microsoft.Extensions.Primitives.IChangeToken GetChangeToken(); } - public partial interface IOptionsFactory where TOptions : class + public partial interface IOptionsFactory<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] TOptions> where TOptions : class { TOptions Create(string name); } - public partial interface IOptionsMonitorCache where TOptions : class + public partial interface IOptionsMonitorCache<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] TOptions> where TOptions : class { void Clear(); TOptions GetOrAdd(string name, System.Func createOptions); bool TryAdd(string name, TOptions options); bool TryRemove(string name); } - public partial interface IOptionsMonitor + public partial interface IOptionsMonitor<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] out TOptions> { TOptions CurrentValue { get; } TOptions Get(string name); System.IDisposable OnChange(System.Action listener); } - public partial interface IOptionsSnapshot : Microsoft.Extensions.Options.IOptions where TOptions : class + public partial interface IOptionsSnapshot<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] out TOptions> : Microsoft.Extensions.Options.IOptions where TOptions : class { TOptions Get(string name); } - public partial interface IOptions where TOptions : class + public partial interface IOptions<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] out TOptions> where TOptions : class { TOptions Value { get; } } @@ -142,7 +142,7 @@ public partial interface IValidateOptions where TOptions : class public static partial class Options { public static readonly string DefaultName; - public static Microsoft.Extensions.Options.IOptions Create(TOptions options) where TOptions : class { throw null; } + public static Microsoft.Extensions.Options.IOptions Create<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] TOptions>(TOptions options) where TOptions : class { throw null; } } public partial class OptionsBuilder where TOptions : class { @@ -174,7 +174,7 @@ public OptionsBuilder(Microsoft.Extensions.DependencyInjection.IServiceCollectio public virtual Microsoft.Extensions.Options.OptionsBuilder Validate(System.Func validation) { throw null; } public virtual Microsoft.Extensions.Options.OptionsBuilder Validate(System.Func validation, string failureMessage) { throw null; } } - public partial class OptionsCache : Microsoft.Extensions.Options.IOptionsMonitorCache where TOptions : class + public partial class OptionsCache<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] TOptions> : Microsoft.Extensions.Options.IOptionsMonitorCache where TOptions : class { public OptionsCache() { } public void Clear() { } @@ -182,14 +182,14 @@ public void Clear() { } public virtual bool TryAdd(string name, TOptions options) { throw null; } public virtual bool TryRemove(string name) { throw null; } } - public partial class OptionsFactory : Microsoft.Extensions.Options.IOptionsFactory where TOptions : class + public partial class OptionsFactory<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] TOptions> : Microsoft.Extensions.Options.IOptionsFactory where TOptions : class { public OptionsFactory(System.Collections.Generic.IEnumerable> setups, System.Collections.Generic.IEnumerable> postConfigures) { } public OptionsFactory(System.Collections.Generic.IEnumerable> setups, System.Collections.Generic.IEnumerable> postConfigures, System.Collections.Generic.IEnumerable> validations) { } public TOptions Create(string name) { throw null; } protected virtual TOptions CreateInstance(string name) { throw null; } } - public partial class OptionsManager : Microsoft.Extensions.Options.IOptions, Microsoft.Extensions.Options.IOptionsSnapshot where TOptions : class + public partial class OptionsManager<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] TOptions> : Microsoft.Extensions.Options.IOptions, Microsoft.Extensions.Options.IOptionsSnapshot where TOptions : class { public OptionsManager(Microsoft.Extensions.Options.IOptionsFactory factory) { } public TOptions Value { get { throw null; } } @@ -197,9 +197,9 @@ public OptionsManager(Microsoft.Extensions.Options.IOptionsFactory fac } public static partial class OptionsMonitorExtensions { - public static System.IDisposable OnChange(this Microsoft.Extensions.Options.IOptionsMonitor monitor, System.Action listener) { throw null; } + public static System.IDisposable OnChange<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] TOptions>(this Microsoft.Extensions.Options.IOptionsMonitor monitor, System.Action listener) { throw null; } } - public partial class OptionsMonitor : Microsoft.Extensions.Options.IOptionsMonitor, System.IDisposable where TOptions : class + public partial class OptionsMonitor<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] TOptions> : Microsoft.Extensions.Options.IOptionsMonitor, System.IDisposable where TOptions : class { public OptionsMonitor(Microsoft.Extensions.Options.IOptionsFactory factory, System.Collections.Generic.IEnumerable> sources, Microsoft.Extensions.Options.IOptionsMonitorCache cache) { } public TOptions CurrentValue { get { throw null; } } @@ -215,7 +215,7 @@ public OptionsValidationException(string optionsName, System.Type optionsType, S public string OptionsName { get { throw null; } } public System.Type OptionsType { get { throw null; } } } - public partial class OptionsWrapper : Microsoft.Extensions.Options.IOptions where TOptions : class + public partial class OptionsWrapper<[System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] TOptions> : Microsoft.Extensions.Options.IOptions where TOptions : class { public OptionsWrapper(TOptions options) { } public TOptions Value { get { throw null; } } diff --git a/src/libraries/Microsoft.Extensions.Options/ref/Microsoft.Extensions.Options.csproj b/src/libraries/Microsoft.Extensions.Options/ref/Microsoft.Extensions.Options.csproj index a71d9b27e5996..c441c3ec38a19 100644 --- a/src/libraries/Microsoft.Extensions.Options/ref/Microsoft.Extensions.Options.csproj +++ b/src/libraries/Microsoft.Extensions.Options/ref/Microsoft.Extensions.Options.csproj @@ -4,6 +4,8 @@ + + diff --git a/src/libraries/Microsoft.Extensions.Options/src/IOptions.cs b/src/libraries/Microsoft.Extensions.Options/src/IOptions.cs index de08efd501d2e..0ceca9fb0c946 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/IOptions.cs +++ b/src/libraries/Microsoft.Extensions.Options/src/IOptions.cs @@ -1,13 +1,16 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; + namespace Microsoft.Extensions.Options { /// /// Used to retrieve configured instances. /// /// The type of options being requested. - public interface IOptions where TOptions : class + public interface IOptions<[DynamicallyAccessedMembers(Options.DynamicallyAccessedMembers)] out TOptions> + where TOptions : class { /// /// The default configured instance diff --git a/src/libraries/Microsoft.Extensions.Options/src/IOptionsFactory.cs b/src/libraries/Microsoft.Extensions.Options/src/IOptionsFactory.cs index e8d8a17a8476c..82077f13cef7e 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/IOptionsFactory.cs +++ b/src/libraries/Microsoft.Extensions.Options/src/IOptionsFactory.cs @@ -1,13 +1,16 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; + namespace Microsoft.Extensions.Options { /// /// Used to create instances. /// /// The type of options being requested. - public interface IOptionsFactory where TOptions : class + public interface IOptionsFactory<[DynamicallyAccessedMembers(Options.DynamicallyAccessedMembers)] TOptions> + where TOptions : class { /// /// Returns a configured instance with the given name. diff --git a/src/libraries/Microsoft.Extensions.Options/src/IOptionsMonitor.cs b/src/libraries/Microsoft.Extensions.Options/src/IOptionsMonitor.cs index 9f01a495de941..10c51cba1aac3 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/IOptionsMonitor.cs +++ b/src/libraries/Microsoft.Extensions.Options/src/IOptionsMonitor.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Diagnostics.CodeAnalysis; namespace Microsoft.Extensions.Options { @@ -9,7 +10,7 @@ namespace Microsoft.Extensions.Options /// Used for notifications when instances change. /// /// The options type. - public interface IOptionsMonitor + public interface IOptionsMonitor<[DynamicallyAccessedMembers(Options.DynamicallyAccessedMembers)] out TOptions> { /// /// Returns the current instance with the . diff --git a/src/libraries/Microsoft.Extensions.Options/src/IOptionsMonitorCache.cs b/src/libraries/Microsoft.Extensions.Options/src/IOptionsMonitorCache.cs index 0706192059d4f..f06062d3eae00 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/IOptionsMonitorCache.cs +++ b/src/libraries/Microsoft.Extensions.Options/src/IOptionsMonitorCache.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Diagnostics.CodeAnalysis; namespace Microsoft.Extensions.Options { @@ -9,7 +10,8 @@ namespace Microsoft.Extensions.Options /// Used by to cache instances. /// /// The type of options being requested. - public interface IOptionsMonitorCache where TOptions : class + public interface IOptionsMonitorCache<[DynamicallyAccessedMembers(Options.DynamicallyAccessedMembers)] TOptions> + where TOptions : class { /// /// Gets a named options instance, or adds a new instance created with . diff --git a/src/libraries/Microsoft.Extensions.Options/src/IOptionsSnapshot.cs b/src/libraries/Microsoft.Extensions.Options/src/IOptionsSnapshot.cs index 603be4b7c857f..d29a381f0cb5a 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/IOptionsSnapshot.cs +++ b/src/libraries/Microsoft.Extensions.Options/src/IOptionsSnapshot.cs @@ -1,13 +1,17 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; + namespace Microsoft.Extensions.Options { /// /// Used to access the value of for the lifetime of a request. /// /// Options type. - public interface IOptionsSnapshot : IOptions where TOptions : class + public interface IOptionsSnapshot<[DynamicallyAccessedMembers(Options.DynamicallyAccessedMembers)] out TOptions> : + IOptions + where TOptions : class { /// /// Returns a configured instance with the given name. diff --git a/src/libraries/Microsoft.Extensions.Options/src/Microsoft.Extensions.Options.csproj b/src/libraries/Microsoft.Extensions.Options/src/Microsoft.Extensions.Options.csproj index d9840099d4ed2..4da5f5e410f28 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/Microsoft.Extensions.Options.csproj +++ b/src/libraries/Microsoft.Extensions.Options/src/Microsoft.Extensions.Options.csproj @@ -7,6 +7,11 @@ false + + + + + diff --git a/src/libraries/Microsoft.Extensions.Options/src/Options.cs b/src/libraries/Microsoft.Extensions.Options/src/Options.cs index bd9ca34ef6431..7c6ea6bc34f6f 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/Options.cs +++ b/src/libraries/Microsoft.Extensions.Options/src/Options.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; + namespace Microsoft.Extensions.Options { /// @@ -8,6 +10,9 @@ namespace Microsoft.Extensions.Options /// public static class Options { + // By default, we're going to keep public, parameterless constructor on any Options class. + internal const DynamicallyAccessedMemberTypes DynamicallyAccessedMembers = DynamicallyAccessedMemberTypes.PublicParameterlessConstructor; + /// /// The default name used for options instances: "". /// @@ -19,7 +24,8 @@ public static class Options /// Options type. /// Options object. /// Wrapped options object. - public static IOptions Create(TOptions options) where TOptions : class + public static IOptions Create<[DynamicallyAccessedMembers(DynamicallyAccessedMembers)] TOptions>(TOptions options) + where TOptions : class { return new OptionsWrapper(options); } diff --git a/src/libraries/Microsoft.Extensions.Options/src/OptionsCache.cs b/src/libraries/Microsoft.Extensions.Options/src/OptionsCache.cs index 8bf2b3388b2ff..b4094fe54de20 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/OptionsCache.cs +++ b/src/libraries/Microsoft.Extensions.Options/src/OptionsCache.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Concurrent; +using System.Diagnostics.CodeAnalysis; namespace Microsoft.Extensions.Options { @@ -10,7 +11,9 @@ namespace Microsoft.Extensions.Options /// Used to cache instances. /// /// The type of options being requested. - public class OptionsCache : IOptionsMonitorCache where TOptions : class + public class OptionsCache<[DynamicallyAccessedMembers(Options.DynamicallyAccessedMembers)] TOptions> : + IOptionsMonitorCache + where TOptions : class { private readonly ConcurrentDictionary> _cache = new ConcurrentDictionary>(StringComparer.Ordinal); diff --git a/src/libraries/Microsoft.Extensions.Options/src/OptionsFactory.cs b/src/libraries/Microsoft.Extensions.Options/src/OptionsFactory.cs index c20cd9ee3a374..dec163c398d33 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/OptionsFactory.cs +++ b/src/libraries/Microsoft.Extensions.Options/src/OptionsFactory.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; namespace Microsoft.Extensions.Options { @@ -10,7 +11,9 @@ namespace Microsoft.Extensions.Options /// Implementation of . /// /// The type of options being requested. - public class OptionsFactory : IOptionsFactory where TOptions : class + public class OptionsFactory<[DynamicallyAccessedMembers(Options.DynamicallyAccessedMembers)] TOptions> : + IOptionsFactory + where TOptions : class { private readonly IEnumerable> _setups; private readonly IEnumerable> _postConfigures; diff --git a/src/libraries/Microsoft.Extensions.Options/src/OptionsManager.cs b/src/libraries/Microsoft.Extensions.Options/src/OptionsManager.cs index 20182ab52109e..71b5a134f3513 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/OptionsManager.cs +++ b/src/libraries/Microsoft.Extensions.Options/src/OptionsManager.cs @@ -1,13 +1,18 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; + namespace Microsoft.Extensions.Options { /// /// Implementation of and . /// /// Options type. - public class OptionsManager : IOptions, IOptionsSnapshot where TOptions : class + public class OptionsManager<[DynamicallyAccessedMembers(Options.DynamicallyAccessedMembers)] TOptions> : + IOptions, + IOptionsSnapshot + where TOptions : class { private readonly IOptionsFactory _factory; private readonly OptionsCache _cache = new OptionsCache(); // Note: this is a private cache diff --git a/src/libraries/Microsoft.Extensions.Options/src/OptionsMonitor.cs b/src/libraries/Microsoft.Extensions.Options/src/OptionsMonitor.cs index 6fe92a3c40f82..7c43e2864cdf6 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/OptionsMonitor.cs +++ b/src/libraries/Microsoft.Extensions.Options/src/OptionsMonitor.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.Primitives; namespace Microsoft.Extensions.Options @@ -11,7 +12,10 @@ namespace Microsoft.Extensions.Options /// Implementation of . /// /// Options type. - public class OptionsMonitor : IOptionsMonitor, IDisposable where TOptions : class + public class OptionsMonitor<[DynamicallyAccessedMembers(Options.DynamicallyAccessedMembers)] TOptions> : + IOptionsMonitor, + IDisposable + where TOptions : class { private readonly IOptionsMonitorCache _cache; private readonly IOptionsFactory _factory; diff --git a/src/libraries/Microsoft.Extensions.Options/src/OptionsMonitorExtensions.cs b/src/libraries/Microsoft.Extensions.Options/src/OptionsMonitorExtensions.cs index aecb3ec75800f..518a5744f85b8 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/OptionsMonitorExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Options/src/OptionsMonitorExtensions.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Diagnostics.CodeAnalysis; namespace Microsoft.Extensions.Options { @@ -16,7 +17,9 @@ public static class OptionsMonitorExtensions /// The IOptionsMonitor. /// The action to be invoked when has changed. /// An which should be disposed to stop listening for changes. - public static IDisposable OnChange(this IOptionsMonitor monitor, Action listener) - => monitor.OnChange((o, _) => listener(o)); + public static IDisposable OnChange<[DynamicallyAccessedMembers(Options.DynamicallyAccessedMembers)] TOptions>( + this IOptionsMonitor monitor, + Action listener) + => monitor.OnChange((o, _) => listener(o)); } } diff --git a/src/libraries/Microsoft.Extensions.Options/src/OptionsServiceCollectionExtensions.cs b/src/libraries/Microsoft.Extensions.Options/src/OptionsServiceCollectionExtensions.cs index 2a1aec0395ab0..10341d4e217d5 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/OptionsServiceCollectionExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Options/src/OptionsServiceCollectionExtensions.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -140,8 +141,10 @@ public static IServiceCollection PostConfigureAll(this IServiceCollect /// The type that will configure options. /// The to add the services to. /// The so that additional calls can be chained. - public static IServiceCollection ConfigureOptions(this IServiceCollection services) where TConfigureOptions : class - => services.ConfigureOptions(typeof(TConfigureOptions)); + public static IServiceCollection ConfigureOptions<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TConfigureOptions>( + this IServiceCollection services) + where TConfigureOptions : class + => services.ConfigureOptions(typeof(TConfigureOptions)); private static bool IsAction(Type type) => (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Action<>)); @@ -174,7 +177,9 @@ private static IEnumerable FindConfigurationServices(Type type) /// The to add the services to. /// The type that will configure options. /// The so that additional calls can be chained. - public static IServiceCollection ConfigureOptions(this IServiceCollection services, Type configureType) + public static IServiceCollection ConfigureOptions( + this IServiceCollection services, + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type configureType) { services.AddOptions(); IEnumerable serviceTypes = FindConfigurationServices(configureType); diff --git a/src/libraries/Microsoft.Extensions.Options/src/OptionsWrapper.cs b/src/libraries/Microsoft.Extensions.Options/src/OptionsWrapper.cs index ca47d5e782198..cdc295802aac1 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/OptionsWrapper.cs +++ b/src/libraries/Microsoft.Extensions.Options/src/OptionsWrapper.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; +using System.Diagnostics.CodeAnalysis; namespace Microsoft.Extensions.Options { @@ -9,7 +9,9 @@ namespace Microsoft.Extensions.Options /// wrapper that returns the options instance. /// /// Options type. - public class OptionsWrapper : IOptions where TOptions : class + public class OptionsWrapper<[DynamicallyAccessedMembers(Options.DynamicallyAccessedMembers)] TOptions> : + IOptions + where TOptions : class { /// /// Intializes the wrapper with the options instance to return. diff --git a/src/libraries/Microsoft.Extensions.Options/tests/ComplexOptions.cs b/src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests/ComplexOptions.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.Options/tests/ComplexOptions.cs rename to src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests/ComplexOptions.cs diff --git a/src/libraries/Microsoft.Extensions.Options/tests/FakeChangeToken.cs b/src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests/FakeChangeToken.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.Options/tests/FakeChangeToken.cs rename to src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests/FakeChangeToken.cs diff --git a/src/libraries/Microsoft.Extensions.Options/tests/FakeOptions.cs b/src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests/FakeOptions.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.Options/tests/FakeOptions.cs rename to src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests/FakeOptions.cs diff --git a/src/libraries/Microsoft.Extensions.Options/tests/FakeOptionsFactory.cs b/src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests/FakeOptionsFactory.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.Options/tests/FakeOptionsFactory.cs rename to src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests/FakeOptionsFactory.cs diff --git a/src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests.csproj b/src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests/Microsoft.Extensions.Options.Tests.csproj similarity index 100% rename from src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests.csproj rename to src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests/Microsoft.Extensions.Options.Tests.csproj diff --git a/src/libraries/Microsoft.Extensions.Options/tests/OptionsBuilderTest.cs b/src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests/OptionsBuilderTest.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.Options/tests/OptionsBuilderTest.cs rename to src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests/OptionsBuilderTest.cs diff --git a/src/libraries/Microsoft.Extensions.Options/tests/OptionsFactoryTests.cs b/src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests/OptionsFactoryTests.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.Options/tests/OptionsFactoryTests.cs rename to src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests/OptionsFactoryTests.cs diff --git a/src/libraries/Microsoft.Extensions.Options/tests/OptionsMonitorTest.cs b/src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests/OptionsMonitorTest.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.Options/tests/OptionsMonitorTest.cs rename to src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests/OptionsMonitorTest.cs diff --git a/src/libraries/Microsoft.Extensions.Options/tests/OptionsSnapshotTest.cs b/src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests/OptionsSnapshotTest.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.Options/tests/OptionsSnapshotTest.cs rename to src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests/OptionsSnapshotTest.cs diff --git a/src/libraries/Microsoft.Extensions.Options/tests/OptionsTest.cs b/src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests/OptionsTest.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.Options/tests/OptionsTest.cs rename to src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests/OptionsTest.cs diff --git a/src/libraries/Microsoft.Extensions.Options/tests/OptionsValidationTests.cs b/src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests/OptionsValidationTests.cs similarity index 100% rename from src/libraries/Microsoft.Extensions.Options/tests/OptionsValidationTests.cs rename to src/libraries/Microsoft.Extensions.Options/tests/Microsoft.Extensions.Options.Tests/OptionsValidationTests.cs diff --git a/src/libraries/Microsoft.Extensions.Options/tests/TrimmingTests/ConfigureTests.cs b/src/libraries/Microsoft.Extensions.Options/tests/TrimmingTests/ConfigureTests.cs new file mode 100644 index 0000000000000..469c6d64b6422 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Options/tests/TrimmingTests/ConfigureTests.cs @@ -0,0 +1,78 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using System; + +class Program +{ + static int Main(string[] args) + { + ServiceCollection services = new ServiceCollection(); + services.Configure(o => + { + o.OptionValue = 99; + }); + services.ConfigureOptions(); + services.AddOptions() + .Configure>((b, a) => + { + b.OptionString = a.Value.OptionValue.ToString(); + }); + + ServiceProvider provider = services.BuildServiceProvider(); + + OptionsA optionsA = provider.GetService>().Value; + OptionsB optionsB = provider.GetService>().Value; + OptionsC optionsC = provider.GetService>().Value; + OptionsD optionsD = provider.GetService>().Create(string.Empty); + + if (optionsA.OptionValue != 99 || + optionsA.PostConfigureOption != 101 || + optionsB.OptionString != "99" || + optionsC is null || + optionsD is null) + { + return -1; + } + + return 100; + } + + private class OptionsA + { + public int OptionValue { get; set; } + public int PostConfigureOption { get; set; } + } + + private class OptionsAPostConfigure : IPostConfigureOptions + { + public void PostConfigure(string name, OptionsA options) + { + if (name.Length != 0) + { + throw new ArgumentException("name must be empty", nameof(name)); + } + + options.PostConfigureOption = 101; + } + } + + private class OptionsB + { + public string OptionString { get; set; } + } + + // Note: OptionsC is never configured + private class OptionsC + { + public string OptionString { get; set; } + } + + // Note: OptionsD is never configured + private class OptionsD + { + public string OptionString { get; set; } + } +} diff --git a/src/libraries/Microsoft.Extensions.Options/tests/TrimmingTests/Microsoft.Extensions.Options.TrimmingTests.proj b/src/libraries/Microsoft.Extensions.Options/tests/TrimmingTests/Microsoft.Extensions.Options.TrimmingTests.proj new file mode 100644 index 0000000000000..669ac862ad7b1 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Options/tests/TrimmingTests/Microsoft.Extensions.Options.TrimmingTests.proj @@ -0,0 +1,16 @@ + + + + + + Microsoft.Extensions.Options; + Microsoft.Extensions.DependencyInjection + + + + + + + + + From 565a993d66f9d4aae54237565fd8111dab231b8a Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Mon, 3 Aug 2020 20:40:50 -0500 Subject: [PATCH 2/2] Respond to PR feedback. --- .../tests/TrimmingTests/ConfigureTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Microsoft.Extensions.Options/tests/TrimmingTests/ConfigureTests.cs b/src/libraries/Microsoft.Extensions.Options/tests/TrimmingTests/ConfigureTests.cs index 469c6d64b6422..870b27bbe9e10 100644 --- a/src/libraries/Microsoft.Extensions.Options/tests/TrimmingTests/ConfigureTests.cs +++ b/src/libraries/Microsoft.Extensions.Options/tests/TrimmingTests/ConfigureTests.cs @@ -24,7 +24,7 @@ static int Main(string[] args) ServiceProvider provider = services.BuildServiceProvider(); OptionsA optionsA = provider.GetService>().Value; - OptionsB optionsB = provider.GetService>().Value; + OptionsB optionsB = provider.GetService>().CurrentValue; OptionsC optionsC = provider.GetService>().Value; OptionsD optionsD = provider.GetService>().Create(string.Empty);