Skip to content

Commit 62a81fe

Browse files
docs: Add OpenFeature.Hosting README (#582)
* Add OpenFeature.Hosting package README Signed-off-by: Kyle Julian <[email protected]> * Address issue with DependencyInjection README not being included Signed-off-by: Kyle Julian <[email protected]> * Update repo README with new guidance on how to using Hosting Signed-off-by: Kyle Julian <[email protected]> * Address PR comments Signed-off-by: Kyle Julian <[email protected]> --------- Signed-off-by: Kyle Julian <[email protected]>
1 parent 95ae7f0 commit 62a81fe

File tree

4 files changed

+147
-6
lines changed

4 files changed

+147
-6
lines changed

README.md

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -533,14 +533,13 @@ For a complete example, see the [AspNetCore sample](./samples/AspNetCore/README.
533533
### Dependency Injection
534534
535535
> [!NOTE]
536-
> 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.
536+
> The OpenFeature.Hosting package is currently experimental. The Hosting package streamlines the integration of OpenFeature within .NET applications, allowing for seamless configuration and lifecycle management of feature flag providers using dependency injection and hosting services.
537537
538538
#### Installation
539539
540-
To set up dependency injection and hosting capabilities for OpenFeature, install the following packages:
540+
To set up dependency injection and hosting capabilities for OpenFeature, install the following package:
541541
542542
```sh
543-
dotnet add package OpenFeature.DependencyInjection
544543
dotnet add package OpenFeature.Hosting
545544
```
546545
@@ -553,7 +552,6 @@ For a basic configuration, you can use the InMemoryProvider. This provider is si
553552
```csharp
554553
builder.Services.AddOpenFeature(featureBuilder => {
555554
featureBuilder
556-
.AddHostedFeatureLifecycle() // From Hosting package
557555
.AddInMemoryProvider();
558556
});
559557
```
@@ -575,7 +573,6 @@ builder.Services.AddOpenFeature(featureBuilder => {
575573
```csharp
576574
builder.Services.AddOpenFeature(featureBuilder => {
577575
featureBuilder
578-
.AddHostedFeatureLifecycle()
579576
.AddContext((contextBuilder, serviceProvider) => { /* Custom context configuration */ })
580577
.AddHook((serviceProvider) => new LoggingHook( /* Custom configuration */ ))
581578
.AddHook(new MetricsHook())

src/OpenFeature.DependencyInjection/OpenFeature.DependencyInjection.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<PropertyGroup>
44
<TargetFrameworks>netstandard2.0;net8.0;net9.0;net462</TargetFrameworks>
55
<RootNamespace>OpenFeature.DependencyInjection</RootNamespace>
6+
<PackageReadmeFile>README.md</PackageReadmeFile>
67
</PropertyGroup>
78

89
<ItemGroup>
@@ -17,7 +18,7 @@
1718
<ItemGroup>
1819
<InternalsVisibleTo Include="$(AssemblyName).Tests" />
1920
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
20-
<None Include="../../README.md" Pack="true" PackagePath="/" />
21+
<None Include="README.md" Pack="true" PackagePath="/" />
2122
</ItemGroup>
2223

2324
</Project>

src/OpenFeature.Hosting/OpenFeature.Hosting.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<PropertyGroup>
44
<TargetFrameworks>netstandard2.0;net8.0;net9.0;net462</TargetFrameworks>
55
<RootNamespace>OpenFeature</RootNamespace>
6+
<PackageReadmeFile>README.md</PackageReadmeFile>
67
</PropertyGroup>
78

89
<ItemGroup>
@@ -16,6 +17,7 @@
1617
<ItemGroup>
1718
<InternalsVisibleTo Include="$(AssemblyName).Tests" />
1819
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
20+
<None Include="README.md" Pack="true" PackagePath="/" />
1921
</ItemGroup>
2022

2123
</Project>

src/OpenFeature.Hosting/README.md

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# OpenFeature.Hosting
2+
3+
[![NuGet](https://img.shields.io/nuget/vpre/OpenFeature.Hosting?label=OpenFeature.Hosting&style=for-the-badge)](https://www.nuget.org/packages/OpenFeature.Hosting)
4+
[![Specification](https://img.shields.io/static/v1?label=specification&message=v0.8.0&color=yellow&style=for-the-badge)](https://github.com/open-feature/spec/releases/tag/v0.8.0)
5+
6+
OpenFeature.Hosting is an extension for the [OpenFeature .NET SDK](https://github.com/open-feature/dotnet-sdk) that streamlines integration with .NET applications using dependency injection and hosting. It enables seamless configuration and lifecycle management of feature flag providers, hooks, and evaluation context using idiomatic .NET patterns.
7+
8+
**🧪 The OpenFeature.Hosting package is still considered experimental and may undergo significant changes. Feedback and contributions are welcome!**
9+
10+
## 🚀 Quick Start
11+
12+
### Requirements
13+
14+
- .NET 8+
15+
- .NET Framework 4.6.2+
16+
17+
### Installation
18+
19+
Add the package to your project:
20+
21+
```sh
22+
dotnet add package OpenFeature.Hosting
23+
```
24+
25+
### Basic Usage
26+
27+
Register OpenFeature in your application's dependency injection container (e.g., in `Program.cs` for ASP.NET Core):
28+
29+
```csharp
30+
builder.Services.AddOpenFeature(featureBuilder => {
31+
featureBuilder
32+
.AddInMemoryProvider();
33+
});
34+
```
35+
36+
You can add global evaluation context, hooks, and event handlers as needed:
37+
38+
```csharp
39+
builder.Services.AddOpenFeature(featureBuilder => {
40+
featureBuilder
41+
.AddContext((contextBuilder, serviceProvider) => {
42+
// Custom context configuration
43+
})
44+
.AddHook<LoggingHook>()
45+
.AddHandler(ProviderEventTypes.ProviderReady, (eventDetails) => {
46+
// Handle provider ready event
47+
});
48+
});
49+
```
50+
51+
### Domain-Scoped Providers
52+
53+
To register multiple providers and select a default provider by domain:
54+
55+
```csharp
56+
builder.Services.AddOpenFeature(featureBuilder => {
57+
featureBuilder
58+
.AddInMemoryProvider("default")
59+
.AddInMemoryProvider("beta")
60+
.AddPolicyName(options => {
61+
options.DefaultNameSelector = serviceProvider => "default";
62+
});
63+
});
64+
```
65+
66+
### Registering a Custom Provider
67+
68+
You can register a custom provider using a factory:
69+
70+
```csharp
71+
builder.Services.AddOpenFeature(featureBuilder => {
72+
featureBuilder.AddProvider(provider => {
73+
// Resolve services or configuration as needed
74+
return new MyCustomProvider();
75+
});
76+
});
77+
```
78+
79+
## 🧩 Features
80+
81+
- **Dependency Injection**: Register providers, hooks, and context using the .NET DI container.
82+
- **Domain Support**: Assign providers to logical domains for multi-tenancy or environment separation.
83+
- **Event Handlers**: React to provider lifecycle events (e.g., readiness).
84+
- **Extensibility**: Add custom hooks, context, and providers.
85+
86+
## 🛠️ Example: ASP.NET Core Integration
87+
88+
Below is a simple example of integrating OpenFeature with an ASP.NET Core application using an in-memory provider and a logging hook.
89+
90+
```csharp
91+
var builder = WebApplication.CreateBuilder(args);
92+
93+
builder.Services.AddOpenFeature(featureBuilder => {
94+
featureBuilder
95+
.AddInMemoryProvider()
96+
.AddHook<LoggingHook>();
97+
});
98+
99+
var app = builder.Build();
100+
101+
app.MapGet("/", async (IFeatureClient client) => {
102+
bool enabled = await client.GetBooleanValueAsync("my-flag", false);
103+
return enabled ? "Feature enabled!" : "Feature disabled.";
104+
});
105+
106+
app.Run();
107+
```
108+
109+
If you have multiple providers registered, you can specify which client and provider to resolve by using the `FromKeyedServices` attribute:
110+
111+
```csharp
112+
var builder = WebApplication.CreateBuilder(args);
113+
114+
builder.Services.AddOpenFeature(featureBuilder => {
115+
featureBuilder
116+
.AddInMemoryProvider("default")
117+
.AddInMemoryProvider("beta")
118+
.AddPolicyName(options => {
119+
options.DefaultNameSelector = serviceProvider => "default";
120+
});
121+
});
122+
123+
var app = builder.Build();
124+
125+
app.MapGet("/", async ([FromKeyedServices("beta")] IFeatureClient client) => {
126+
bool enabled = await client.GetBooleanValueAsync("my-flag", false);
127+
return enabled ? "Feature enabled!" : "Feature disabled.";
128+
});
129+
130+
app.Run();
131+
```
132+
133+
## 📚 Further Reading
134+
135+
- [OpenFeature .NET SDK Documentation](https://github.com/open-feature/dotnet-sdk)
136+
- [OpenFeature Specification](https://openfeature.dev)
137+
- [Samples](https://github.com/open-feature/dotnet-sdk/blob/main/samples/AspNetCore/README.md)
138+
139+
## 🤝 Contributing
140+
141+
Contributions are welcome! See the [CONTRIBUTING](https://github.com/open-feature/dotnet-sdk/blob/main/CONTRIBUTING.md) guide for details.

0 commit comments

Comments
 (0)