Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add Dependency Injection and Hosting support for OpenFeature #310

Open
wants to merge 136 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
136 commits
Select commit Hold shift + click to select a range
963b54c
[SIP-123] feat: Create OpenFeature.DependencyInjection project
arttonoyan Oct 4, 2024
a803429
chore: Update TargetFrameworks to net6.0
arttonoyan Oct 4, 2024
79ee277
feat: Create OpenFeatureBuilder record
arttonoyan Oct 4, 2024
9f3c40e
feat: Add OpenFeatureBuilderExtensions
arttonoyan Oct 4, 2024
6786bd8
feat: Add IFeatureLifecycleManager interface and implementation
arttonoyan Oct 4, 2024
f373eb0
feat: Add OpenFeatureServiceCollectionExtensions
arttonoyan Oct 4, 2024
1f86298
feat: Add AddProvider extension method in OpenFeatureBuilderExtensions
arttonoyan Oct 8, 2024
f1039a2
feat: Add AddProvider extension method in OpenFeatureServiceCollectio…
arttonoyan Oct 13, 2024
5905cc6
test: Add OpenFeatureBuilderExtensionsTests
arttonoyan Oct 13, 2024
6c3c15e
test: Add unit tests for AddProvider method in OpenFeatureBuilderExte…
arttonoyan Oct 13, 2024
bd20d40
feat: Replicate NoOpFeatureProvider implementation from src/OpenFeatu…
arttonoyan Oct 13, 2024
441aa4f
test: Update OpenFeatureBuilderExtensionsTests with NoOpFeatureProvid…
arttonoyan Oct 13, 2024
fa04665
test: Add OpenFeatureBuilderExtensionsTests
arttonoyan Oct 13, 2024
fcea8a6
refactor: Remove ExcludeFromCodeCoverage attribute from FeatureLifecy…
arttonoyan Oct 13, 2024
fc8dcab
test: Improve OpenFeatureBuilderExtensionsTests for better coverage a…
arttonoyan Oct 13, 2024
0a996aa
test: Create OpenFeatureServiceCollectionExtensionsTests
arttonoyan Oct 13, 2024
76e1816
feat: Create OpenFeature.Hosting project
arttonoyan Oct 13, 2024
84dd0e0
feat: Add HostedFeatureLifecycleService and related logic
arttonoyan Oct 13, 2024
572d67b
test: Improve EnsureInitializedAsync_ShouldThrowException_WhenProvide…
arttonoyan Oct 14, 2024
d7e5fbb
[SIP-123] feat: Create OpenFeature.DependencyInjection project
arttonoyan Oct 4, 2024
f60b5d8
chore: Update TargetFrameworks to net6.0
arttonoyan Oct 4, 2024
8b59e53
feat: Create OpenFeatureBuilder record
arttonoyan Oct 4, 2024
c644df6
feat: Add OpenFeatureBuilderExtensions
arttonoyan Oct 4, 2024
f4f108b
feat: Add IFeatureLifecycleManager interface and implementation
arttonoyan Oct 4, 2024
43bcde9
feat: Add OpenFeatureServiceCollectionExtensions
arttonoyan Oct 4, 2024
47e87c2
feat: Add AddProvider extension method in OpenFeatureBuilderExtensions
arttonoyan Oct 8, 2024
3650de2
feat: Add AddProvider extension method in OpenFeatureServiceCollectio…
arttonoyan Oct 13, 2024
0027489
test: Add OpenFeatureBuilderExtensionsTests
arttonoyan Oct 13, 2024
5638163
test: Add unit tests for AddProvider method in OpenFeatureBuilderExte…
arttonoyan Oct 13, 2024
5de7ceb
feat: Replicate NoOpFeatureProvider implementation from src/OpenFeatu…
arttonoyan Oct 13, 2024
2e99210
test: Update OpenFeatureBuilderExtensionsTests with NoOpFeatureProvid…
arttonoyan Oct 13, 2024
880df92
test: Add OpenFeatureBuilderExtensionsTests
arttonoyan Oct 13, 2024
9258706
refactor: Remove ExcludeFromCodeCoverage attribute from FeatureLifecy…
arttonoyan Oct 13, 2024
19664b0
test: Improve OpenFeatureBuilderExtensionsTests for better coverage a…
arttonoyan Oct 13, 2024
9c21943
test: Create OpenFeatureServiceCollectionExtensionsTests
arttonoyan Oct 13, 2024
a23c5ea
feat: Create OpenFeature.Hosting project
arttonoyan Oct 13, 2024
7906a3b
feat: Add HostedFeatureLifecycleService and related logic
arttonoyan Oct 13, 2024
1850159
test: Improve EnsureInitializedAsync_ShouldThrowException_WhenProvide…
arttonoyan Oct 14, 2024
63ead66
Merge branch 'add-dependency-injection' of https://github.com/arttono…
arttonoyan Oct 14, 2024
70708ec
fix(build): Resolve MultiTarget framework build errors
arttonoyan Oct 14, 2024
d615b04
chore(deps): update codecov/codecov-action action to v4.5.0 (#272)
renovate[bot] Jul 3, 2024
ad95765
chore(deps): update dependency githubactionstestlogger to v2.4.1 (#274)
renovate[bot] Jul 3, 2024
ce23cdc
feat!: internally maintain provider status (#276)
toddbaert Jul 3, 2024
7716f4a
chore: cleanup code (#277)
askpt Jul 23, 2024
12d48c2
chore(deps): update actions/upload-artifact action to v4.3.4 (#278)
renovate[bot] Jul 25, 2024
1f0468e
chore(deps): update xunit-dotnet monorepo (#279)
renovate[bot] Jul 25, 2024
d480da4
chore(deps): update dependency dotnet-sdk to v8.0.303 (#275)
renovate[bot] Jul 25, 2024
cc5f5bc
feat: Drop net7 TFM (#284)
benjiro Jul 26, 2024
90d172c
fix: Should map metadata when converting from ResolutionDetails to Fl…
benjiro Jul 26, 2024
2072e45
feat: back targetingKey with internal map (#287)
toddbaert Jul 29, 2024
c503b30
chore(deps): update actions/upload-artifact action to v4.3.5 (#291)
renovate[bot] Aug 6, 2024
9a5a343
feat!: domain instead of client name (#294)
toddbaert Aug 13, 2024
be43fcc
chore(deps): update dependency benchmarkdotnet to v0.14.0 (#293)
renovate[bot] Aug 14, 2024
84f8e18
chore(deps): update dependency dotnet-sdk to v8.0.400 (#295)
renovate[bot] Aug 14, 2024
94f4d66
chore: in-memory UpdateFlags to UpdateFlagsAsync (#298)
toddbaert Aug 21, 2024
756a7f7
chore(main): release 2.0.0 (#254)
github-actions[bot] Aug 21, 2024
36b5f8c
chore(deps): update dependency microsoft.net.test.sdk to 17.11.0 (#297)
renovate[bot] Sep 4, 2024
c9339ec
chore(deps): update dependency dotnet-sdk to v8.0.401 (#296)
renovate[bot] Sep 5, 2024
980d0be
chore: update release please config (#304)
beeme1mr Sep 24, 2024
d4a5e3d
[SIP-123] feat: Create OpenFeature.DependencyInjection project
arttonoyan Oct 4, 2024
8387def
chore: Update TargetFrameworks to net6.0
arttonoyan Oct 4, 2024
5077a1c
feat: Create OpenFeatureBuilder record
arttonoyan Oct 4, 2024
95e8ddc
feat: Add OpenFeatureBuilderExtensions
arttonoyan Oct 4, 2024
f157496
feat: Add IFeatureLifecycleManager interface and implementation
arttonoyan Oct 4, 2024
49991ec
feat: Add OpenFeatureServiceCollectionExtensions
arttonoyan Oct 4, 2024
5bc2c47
feat: Add AddProvider extension method in OpenFeatureBuilderExtensions
arttonoyan Oct 8, 2024
9ea9b01
feat: Add AddProvider extension method in OpenFeatureServiceCollectio…
arttonoyan Oct 13, 2024
4066b89
test: Add OpenFeatureBuilderExtensionsTests
arttonoyan Oct 13, 2024
367518b
test: Add unit tests for AddProvider method in OpenFeatureBuilderExte…
arttonoyan Oct 13, 2024
70c269f
feat: Replicate NoOpFeatureProvider implementation from src/OpenFeatu…
arttonoyan Oct 13, 2024
b20bc13
test: Update OpenFeatureBuilderExtensionsTests with NoOpFeatureProvid…
arttonoyan Oct 13, 2024
c251f56
test: Add OpenFeatureBuilderExtensionsTests
arttonoyan Oct 13, 2024
8b2ab4b
refactor: Remove ExcludeFromCodeCoverage attribute from FeatureLifecy…
arttonoyan Oct 13, 2024
3800447
test: Improve OpenFeatureBuilderExtensionsTests for better coverage a…
arttonoyan Oct 13, 2024
e111714
test: Create OpenFeatureServiceCollectionExtensionsTests
arttonoyan Oct 13, 2024
cb63b1c
feat: Create OpenFeature.Hosting project
arttonoyan Oct 13, 2024
0e53494
feat: Add HostedFeatureLifecycleService and related logic
arttonoyan Oct 13, 2024
dc765e6
test: Improve EnsureInitializedAsync_ShouldThrowException_WhenProvide…
arttonoyan Oct 14, 2024
4f80593
add-dependency-injection
arttonoyan Oct 16, 2024
0a76193
add-dependency-injection
arttonoyan Oct 16, 2024
ac98ddd
add-dependency-injection
arttonoyan Oct 16, 2024
4af39ce
add-dependency-injection
arttonoyan Oct 16, 2024
0fa6dc3
add-dependency-injection
arttonoyan Oct 16, 2024
926c0d4
add-dependency-injection
arttonoyan Oct 16, 2024
9b8d9f2
add-dependency-injection
arttonoyan Oct 16, 2024
aa488ae
feat: Replicate NoOpFeatureProvider implementation from src/OpenFeatu…
arttonoyan Oct 13, 2024
1f8e9e4
add-dependency-injection
arttonoyan Oct 16, 2024
3aaa7df
test: Improve EnsureInitializedAsync_ShouldThrowException_WhenProvide…
arttonoyan Oct 14, 2024
ffef1ac
add-dependency-injection
arttonoyan Oct 16, 2024
1acb4fa
add-dependency-injection
arttonoyan Oct 16, 2024
96889dd
Merge branch 'main' into add-dependency-injection
arttonoyan Oct 16, 2024
54c145e
Fix dotnet format build.
askpt Oct 17, 2024
55582d7
Changing to Source Generation logging.
askpt Oct 18, 2024
8ebdad4
add-dependency-injection
arttonoyan Oct 21, 2024
3089129
Merge branch 'add-dependency-injection' of https://github.com/arttono…
arttonoyan Oct 21, 2024
fe5e072
refactor: Update ThrowIfNull method
arttonoyan Oct 21, 2024
10ea9f1
refactor: Change OpenFeatureBuilder to class and make IsContextConfig…
arttonoyan Oct 22, 2024
3436db5
feat: Implement domain-scoped providers logic
arttonoyan Oct 27, 2024
5738f3c
fix: Correct lines in package.props
arttonoyan Oct 27, 2024
0ce727c
feat(core): Add DependencyInjection namespace for improved modularity
arttonoyan Oct 27, 2024
e8350d7
fix(build): Resolve build error in DependencyInjection namespace
arttonoyan Oct 27, 2024
eaf0319
feat(config): Add PolicyName logic to configure default FeatureClient
arttonoyan Oct 27, 2024
7916d14
refactor(naming): Rename getClient to clientFactory for clarity
arttonoyan Oct 27, 2024
af78c5a
feat(policy): Implement PolicyName logic for enhanced configuration h…
arttonoyan Oct 27, 2024
4fc100e
refactor: Make AddPolicyName extension method public
arttonoyan Oct 27, 2024
d536515
fix: Update AddPolicyName extension method to set IsPolicyConfigured …
arttonoyan Oct 27, 2024
916f60a
feat(extensions): Add AddProvider extension method with default OpenF…
arttonoyan Oct 27, 2024
387a88b
fix(tests): Resolve issues causing test failures
arttonoyan Oct 27, 2024
4ac7f20
refactor(naming): Rename FeatureProviderBuilder to IFeatureProviderFa…
arttonoyan Oct 28, 2024
17a66ca
fix(typo): Correct naming typo for improved readability
arttonoyan Oct 28, 2024
c424b2a
feat(validation): Add check for whitespace or empty values
arttonoyan Oct 29, 2024
1de9096
feat(validation): Add check for whitespace or empty values
arttonoyan Oct 29, 2024
ca44115
Update src/OpenFeature.DependencyInjection/OpenFeatureBuilder.cs
arttonoyan Oct 29, 2024
3d33caa
Update src/OpenFeature.DependencyInjection/OpenFeatureBuilder.cs
arttonoyan Oct 29, 2024
dfd66d1
Update src/OpenFeature.DependencyInjection/OpenFeatureBuilderExtensio…
arttonoyan Oct 29, 2024
d169b0b
Update src/OpenFeature.DependencyInjection/OpenFeatureBuilderExtensio…
arttonoyan Oct 29, 2024
ec6a81b
Update src/OpenFeature.DependencyInjection/OpenFeatureBuilderExtensio…
arttonoyan Oct 29, 2024
a853b52
Update src/OpenFeature.DependencyInjection/OpenFeatureBuilderExtensio…
arttonoyan Oct 29, 2024
6849899
Update src/OpenFeature.DependencyInjection/OpenFeatureBuilderExtensio…
arttonoyan Oct 30, 2024
73bb930
fix: Rename argument from name to domain
arttonoyan Oct 30, 2024
749b18d
fix: Rename property to DomainBoundProviderRegistrationCount
arttonoyan Oct 30, 2024
f6e072d
refactor(namespaces): Move Guard class under DependencyInjection name…
arttonoyan Oct 30, 2024
b6a8e2d
feat: Create InMemoryProviderFactory and FeatureBuilderExtensions
arttonoyan Oct 31, 2024
ce56e84
Merge pull request #1 from arttonoyan/di-domain-scoped-providers
arttonoyan Oct 31, 2024
f1b8a9b
fix(formatting): Correct code formatting issues
arttonoyan Nov 1, 2024
90481c0
Update src/OpenFeature.DependencyInjection/PolicyNameOptions.cs
arttonoyan Nov 1, 2024
8252e47
Update src/OpenFeature.Hosting/HostedFeatureLifecycleService.cs
arttonoyan Nov 1, 2024
9704d2e
fix: Correct namespace issues
arttonoyan Nov 1, 2024
124eb46
feat(diagnostics): Create Diagnostics namespace and add FeatureCodes
arttonoyan Nov 5, 2024
5ea621b
feat(diagnostics): Add experimental attribute in selected classes
arttonoyan Nov 5, 2024
0eceed8
chore(docs): Update summary for FeatureCodes
arttonoyan Nov 9, 2024
6f8c5be
Merge pull request #3 from arttonoyan/feature/add-net8-experimental-a…
arttonoyan Nov 9, 2024
547ba57
Update README.md
arttonoyan Nov 9, 2024
462a4de
fix: Correct incorrect formats
arttonoyan Nov 11, 2024
f908bf5
Merge branch 'main' into add-dependency-injection
arttonoyan Nov 11, 2024
02eccee
docs(OpenFeatureBuilderExtensions): Add exception details
arttonoyan Nov 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
<Project>

<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>

<ItemGroup Label="src">
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.1" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="8.0.2" />
<PackageVersion Include="System.Collections.Immutable" Version="1.7.1" />
<PackageVersion Include="System.Threading.Channels" Version="6.0.0" />
<PackageVersion Include="System.ValueTuple" Version="4.5.0" />
</ItemGroup>

<ItemGroup Label="test">
<PackageVersion Include="AutoFixture" Version="4.18.1" />
<PackageVersion Include="BenchmarkDotNet" Version="0.14.0" />
Expand All @@ -26,10 +29,11 @@
<PackageVersion Include="SpecFlow.xUnit" Version="3.9.74" />
<PackageVersion Include="xunit" Version="2.9.0" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
</ItemGroup>

<ItemGroup Condition="'$(OS)' == 'Unix'">
<PackageVersion Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" />
</ItemGroup>

</Project>
35 changes: 28 additions & 7 deletions OpenFeature.sln
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenFeature.Tests", "test\O
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenFeature.Benchmarks", "test\OpenFeature.Benchmarks\OpenFeature.Benchmarks.csproj", "{90E7EAD3-251E-4490-AF78-E758E33518E5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenFeature.E2ETests", "test\OpenFeature.E2ETests\OpenFeature.E2ETests.csproj", "{7398C446-2630-4F8C-9278-4E807720E9E5}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenFeature.E2ETests", "test\OpenFeature.E2ETests\OpenFeature.E2ETests.csproj", "{7398C446-2630-4F8C-9278-4E807720E9E5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenFeature.DependencyInjection", "src\OpenFeature.DependencyInjection\OpenFeature.DependencyInjection.csproj", "{C5415057-2700-48B5-940A-7A10969FA639}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenFeature.DependencyInjection.Tests", "test\OpenFeature.DependencyInjection.Tests\OpenFeature.DependencyInjection.Tests.csproj", "{EB35F9F6-8A79-410E-A293-9387BC4AC9A7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenFeature.Hosting", "src\OpenFeature.Hosting\OpenFeature.Hosting.csproj", "{C99DA02A-3981-45A6-B3F8-4A1A48653DEE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -101,21 +107,36 @@ Global
{7398C446-2630-4F8C-9278-4E807720E9E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7398C446-2630-4F8C-9278-4E807720E9E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7398C446-2630-4F8C-9278-4E807720E9E5}.Release|Any CPU.Build.0 = Release|Any CPU
{C5415057-2700-48B5-940A-7A10969FA639}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C5415057-2700-48B5-940A-7A10969FA639}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C5415057-2700-48B5-940A-7A10969FA639}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C5415057-2700-48B5-940A-7A10969FA639}.Release|Any CPU.Build.0 = Release|Any CPU
{EB35F9F6-8A79-410E-A293-9387BC4AC9A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EB35F9F6-8A79-410E-A293-9387BC4AC9A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EB35F9F6-8A79-410E-A293-9387BC4AC9A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EB35F9F6-8A79-410E-A293-9387BC4AC9A7}.Release|Any CPU.Build.0 = Release|Any CPU
{C99DA02A-3981-45A6-B3F8-4A1A48653DEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C99DA02A-3981-45A6-B3F8-4A1A48653DEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C99DA02A-3981-45A6-B3F8-4A1A48653DEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C99DA02A-3981-45A6-B3F8-4A1A48653DEE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{9392E03B-4E6B-434C-8553-B859424388B1} = {E8916D4F-B97E-42D6-8620-ED410A106F94}
{2B172AA0-A5A6-4D94-BA1F-B79D59B0C2D8} = {E8916D4F-B97E-42D6-8620-ED410A106F94}
{C4746B8C-FE19-440B-922C-C2377F906FE8} = {2B172AA0-A5A6-4D94-BA1F-B79D59B0C2D8}
{09BAB3A2-E94C-490A-861C-7D1E11BB7024} = {2B172AA0-A5A6-4D94-BA1F-B79D59B0C2D8}
{4BB69DB3-9653-4197-9589-37FA6D658CB7} = {E8916D4F-B97E-42D6-8620-ED410A106F94}
{72005F60-C2E8-40BF-AE95-893635134D7D} = {E8916D4F-B97E-42D6-8620-ED410A106F94}
{07A6E6BD-FB7E-4B3B-9CBE-65AE9D0EB223} = {C97E9975-E10A-4817-AE2C-4DD69C3C02D4}
{49BB42BA-10A6-4DA3-A7D5-38C968D57837} = {65FBA159-23E0-4CF9-881B-F78DBFF198E9}
{90E7EAD3-251E-4490-AF78-E758E33518E5} = {65FBA159-23E0-4CF9-881B-F78DBFF198E9}
{7398C446-2630-4F8C-9278-4E807720E9E5} = {65FBA159-23E0-4CF9-881B-F78DBFF198E9}
{C4746B8C-FE19-440B-922C-C2377F906FE8} = {2B172AA0-A5A6-4D94-BA1F-B79D59B0C2D8}
{09BAB3A2-E94C-490A-861C-7D1E11BB7024} = {2B172AA0-A5A6-4D94-BA1F-B79D59B0C2D8}
{72005F60-C2E8-40BF-AE95-893635134D7D} = {E8916D4F-B97E-42D6-8620-ED410A106F94}
{9392E03B-4E6B-434C-8553-B859424388B1} = {E8916D4F-B97E-42D6-8620-ED410A106F94}
{2B172AA0-A5A6-4D94-BA1F-B79D59B0C2D8} = {E8916D4F-B97E-42D6-8620-ED410A106F94}
{4BB69DB3-9653-4197-9589-37FA6D658CB7} = {E8916D4F-B97E-42D6-8620-ED410A106F94}
{C5415057-2700-48B5-940A-7A10969FA639} = {C97E9975-E10A-4817-AE2C-4DD69C3C02D4}
{EB35F9F6-8A79-410E-A293-9387BC4AC9A7} = {65FBA159-23E0-4CF9-881B-F78DBFF198E9}
{C99DA02A-3981-45A6-B3F8-4A1A48653DEE} = {C97E9975-E10A-4817-AE2C-4DD69C3C02D4}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {41F01B78-FB06-404F-8AD0-6ED6973F948F}
Expand Down
77 changes: 76 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,9 @@ public async Task Example()
| ✅ | [Eventing](#eventing) | React to state changes in the provider or flag management system. |
| ✅ | [Shutdown](#shutdown) | Gracefully clean up a provider during application shutdown. |
| ✅ | [Extending](#extending) | Extend OpenFeature with custom providers and hooks. |
| 🔬 | [DependencyInjection](#DependencyInjection) | Integrate OpenFeature with .NET's dependency injection for streamlined provider setup. |

> Implemented: ✅ | In-progress: ⚠️ | Not implemented yet: ❌
> Implemented: ✅ | In-progress: ⚠️ | Not implemented yet: ❌ | Experimental: 🔬

### Providers

Expand Down Expand Up @@ -300,6 +301,80 @@ public class MyHook : Hook

Built a new hook? [Let us know](https://github.com/open-feature/openfeature.dev/issues/new?assignees=&labels=hook&projects=&template=document-hook.yaml&title=%5BHook%5D%3A+) so we can add it to the docs!

### DependencyInjection
> [!NOTE]
> The OpenFeature.DependencyInjection and OpenFeature.Hosting packages are currently experimental. They streamline the integration of OpenFeature within .NET applications, allowing for seamless configuration and lifecycle management of feature flag providers using dependency injection and hosting services.

#### Installation
To set up dependency injection and hosting capabilities for OpenFeature, install the following packages:
```sh
dotnet add package OpenFeature.DependencyInjection
dotnet add package OpenFeature.Hosting
```
#### Usage Examples
For a basic configuration, you can use the InMemoryProvider. This provider is simple and well-suited for development and testing purposes.

**Basic Configuration:**
```csharp
builder.Services.AddOpenFeature(featureBuilder => {
featureBuilder
.AddHostedFeatureLifecycle() // From Hosting package
.AddContext((contextBuilder, serviceProvider) => { /* Custom context configuration */ })
.AddInMemoryProvider();
});
```
**Domain-Scoped Provider Configuration:**
<br />To set up multiple providers with a selection policy, define logic for choosing the default provider. This example designates `name1` as the default provider:
```csharp
builder.Services.AddOpenFeature(featureBuilder => {
featureBuilder
.AddHostedFeatureLifecycle()
.AddContext((contextBuilder, serviceProvider) => { /* Custom context configuration */ })
.AddInMemoryProvider("name1")
.AddInMemoryProvider("name2")
.AddPolicyName(options => {
// Custom logic to select a default provider
options.DefaultNameSelector = serviceProvider => "name1";
});
});
```
#### Creating a New Provider
To integrate a custom provider, such as InMemoryProvider, you’ll need to create a factory that builds and configures the provider. This section demonstrates how to set up InMemoryProvider as a new provider with custom configuration options.

**Configuring InMemoryProvider as a New Provider**
<br />Begin by creating a custom factory class, `InMemoryProviderFactory`, that implements `IFeatureProviderFactory`. This factory will initialize your provider with any necessary configurations.
```csharp
public class InMemoryProviderFactory : IFeatureProviderFactory
{
internal IDictionary<string, Flag>? Flags { get; set; }

public FeatureProvider Create() => new InMemoryProvider(Flags);
}
```
**Adding an Extension Method to OpenFeatureBuilder**
<br />To streamline the configuration process, add an extension method, `AddInMemoryProvider`, to `OpenFeatureBuilder`. This allows you to set up the provider with either a domain-scoped or a default configuration.

```csharp
public static partial class FeatureBuilderExtensions
{
public static OpenFeatureBuilder AddInMemoryProvider(this OpenFeatureBuilder builder, Action<IDictionary<string, Flag>>? configure = null)
=> builder.AddProvider<InMemoryProviderFactory>(factory => ConfigureFlags(factory, configure));

public static OpenFeatureBuilder AddInMemoryProvider(this OpenFeatureBuilder builder, string domain, Action<IDictionary<string, Flag>>? configure = null)
=> builder.AddProvider<InMemoryProviderFactory>(domain, factory => ConfigureFlags(factory, configure));

private static void ConfigureFlags(InMemoryProviderFactory factory, Action<IDictionary<string, Flag>>? configure)
{
if (configure == null)
return;

var flag = new Dictionary<string, Flag>();
configure.Invoke(flag);
factory.Flags = flag;
}
}
```

<!-- x-hide-in-docs-start -->
## ⭐️ Support the project

Expand Down
38 changes: 38 additions & 0 deletions src/OpenFeature.DependencyInjection/Diagnostics/FeatureCodes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
namespace OpenFeature.DependencyInjection.Diagnostics;

/// <summary>
/// Contains identifiers for experimental features and diagnostics in the OpenFeature framework.
/// </summary>
/// <remarks>
/// <c>Experimental</c> - This class includes identifiers that allow developers to track and conditionally enable
/// experimental features. Each identifier follows a structured code format to indicate the feature domain,
/// maturity level, and unique identifier. Note that experimental features are subject to change or removal
/// in future releases.
/// <para>
/// <strong>Basic Information</strong><br/>
/// These identifiers conform to OpenFeature’s Diagnostics Specifications, allowing developers to recognize
/// and manage experimental features effectively.
/// </para>
/// </remarks>
/// <example>
/// <code>
/// Code Structure:
/// - "OF" - Represents the OpenFeature library.
/// - "DI" - Indicates the Dependency Injection domain.
/// - "001" - Unique identifier for a specific feature.
/// </code>
/// </example>
internal static class FeatureCodes
{
/// <summary>
/// Identifier for the experimental Dependency Injection features within the OpenFeature framework.
/// </summary>
/// <remarks>
/// <c>OFDI001</c> identifier marks experimental features in the Dependency Injection (DI) domain.
///
/// Usage:
/// Developers can use this identifier to conditionally enable or test experimental DI features.
/// It is part of the OpenFeature diagnostics system to help track experimental functionality.
/// </remarks>
public const string NewDi = "OFDI001";
}
20 changes: 20 additions & 0 deletions src/OpenFeature.DependencyInjection/Guard.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;

namespace OpenFeature.DependencyInjection;

[DebuggerStepThrough]
internal static class Guard
{
public static void ThrowIfNull(object? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null)
{
if (argument is null)
throw new ArgumentNullException(paramName);
}

public static void ThrowIfNullOrWhiteSpace(string? argument, [CallerArgumentExpression(nameof(argument))] string? paramName = null)
{
if (string.IsNullOrWhiteSpace(argument))
throw new ArgumentNullException(paramName);
}
}
24 changes: 24 additions & 0 deletions src/OpenFeature.DependencyInjection/IFeatureLifecycleManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace OpenFeature.DependencyInjection;

/// <summary>
/// Defines the contract for managing the lifecycle of a feature api.
/// </summary>
public interface IFeatureLifecycleManager
{
/// <summary>
/// Ensures that the feature provider is properly initialized and ready to be used.
/// This method should handle all necessary checks, configuration, and setup required to prepare the feature provider.
/// </summary>
/// <param name="cancellationToken">Propagates notification that operations should be canceled.</param>
/// <returns>A Task representing the asynchronous operation of initializing the feature provider.</returns>
/// <exception cref="InvalidOperationException">Thrown when the feature provider is not registered or is in an invalid state.</exception>
ValueTask EnsureInitializedAsync(CancellationToken cancellationToken = default);

/// <summary>
/// Gracefully shuts down the feature api, ensuring all resources are properly disposed of and any persistent state is saved.
/// This method should handle all necessary cleanup and shutdown operations for the feature provider.
/// </summary>
/// <param name="cancellationToken">Propagates notification that operations should be canceled.</param>
/// <returns>A Task representing the asynchronous operation of shutting down the feature provider.</returns>
ValueTask ShutdownAsync(CancellationToken cancellationToken = default);
}
23 changes: 23 additions & 0 deletions src/OpenFeature.DependencyInjection/IFeatureProviderFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace OpenFeature.DependencyInjection;

/// <summary>
/// Provides a contract for creating instances of <see cref="FeatureProvider"/>.
/// This factory interface enables custom configuration and initialization of feature providers
/// to support domain-specific or application-specific feature flag management.
/// </summary>
#if NET8_0_OR_GREATER
[System.Diagnostics.CodeAnalysis.Experimental(Diagnostics.FeatureCodes.NewDi)]
#endif
public interface IFeatureProviderFactory
{
/// <summary>
/// Creates an instance of a <see cref="FeatureProvider"/> configured according to
/// the specific settings implemented by the concrete factory.
/// </summary>
/// <returns>
/// A new instance of <see cref="FeatureProvider"/>.
/// The configuration and behavior of this provider instance are determined by
/// the implementation of this method.
/// </returns>
FeatureProvider Create();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace OpenFeature.DependencyInjection.Internal;

internal sealed partial class FeatureLifecycleManager : IFeatureLifecycleManager
{
private readonly Api _featureApi;
private readonly IServiceProvider _serviceProvider;
private readonly ILogger<FeatureLifecycleManager> _logger;

public FeatureLifecycleManager(Api featureApi, IServiceProvider serviceProvider, ILogger<FeatureLifecycleManager> logger)
{
_featureApi = featureApi;
_serviceProvider = serviceProvider;
_logger = logger;
}

/// <inheritdoc />
public async ValueTask EnsureInitializedAsync(CancellationToken cancellationToken = default)
{
this.LogStartingInitializationOfFeatureProvider();

var options = _serviceProvider.GetRequiredService<IOptions<OpenFeatureOptions>>().Value;
if (options.HasDefaultProvider)
{
var featureProvider = _serviceProvider.GetRequiredService<FeatureProvider>();
await _featureApi.SetProviderAsync(featureProvider).ConfigureAwait(false);
}

foreach (var name in options.ProviderNames)
{
var featureProvider = _serviceProvider.GetRequiredKeyedService<FeatureProvider>(name);
await _featureApi.SetProviderAsync(name, featureProvider).ConfigureAwait(false);
}
}

/// <inheritdoc />
public async ValueTask ShutdownAsync(CancellationToken cancellationToken = default)
{
this.LogShuttingDownFeatureProvider();
await _featureApi.ShutdownAsync().ConfigureAwait(false);
}

[LoggerMessage(200, LogLevel.Information, "Starting initialization of the feature provider")]
partial void LogStartingInitializationOfFeatureProvider();

[LoggerMessage(200, LogLevel.Information, "Shutting down the feature provider")]
partial void LogShuttingDownFeatureProvider();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// @formatter:off
// ReSharper disable All
#if NETCOREAPP3_0_OR_GREATER
// https://github.com/dotnet/runtime/issues/96197
[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.CallerArgumentExpressionAttribute))]
#else
#pragma warning disable
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System.Runtime.CompilerServices;

[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
internal sealed class CallerArgumentExpressionAttribute : Attribute
toddbaert marked this conversation as resolved.
Show resolved Hide resolved
{
public CallerArgumentExpressionAttribute(string parameterName)
{
ParameterName = parameterName;
}

public string ParameterName { get; }
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// @formatter:off
// ReSharper disable All
#if NET5_0_OR_GREATER
// https://github.com/dotnet/runtime/issues/96197
[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Runtime.CompilerServices.IsExternalInit))]
#else
#pragma warning disable
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.ComponentModel;

namespace System.Runtime.CompilerServices;

/// <summary>
/// Reserved to be used by the compiler for tracking metadata.
/// This class should not be used by developers in source code.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
static class IsExternalInit { }
#endif
Loading