Skip to content

Commit fca13c2

Browse files
committed
docs: update README.md
1 parent 9c42d4a commit fca13c2

File tree

2 files changed

+185
-112
lines changed

2 files changed

+185
-112
lines changed

Diff for: README.md

+183-111
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<!-- markdownlint-disable MD033 -->
2+
<!-- x-hide-in-docs-start -->
23
<p align="center">
34
<picture>
45
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/open-feature/community/0e23508c163a6a1ac8c0ced3e4bd78faafe627c7/assets/logo/horizontal/white/openfeature-horizontal-white.svg">
@@ -9,32 +10,50 @@
910

1011
<h2 align="center">OpenFeature .NET SDK</h2>
1112

12-
[![a](https://img.shields.io/badge/slack-%40cncf%2Fopenfeature-brightgreen?style=flat&logo=slack)](https://cloud-native.slack.com/archives/C0344AANLA1)
13-
[![spec version badge](https://img.shields.io/badge/Specification-v0.5.2-yellow)](https://github.com/open-feature/spec/tree/v0.5.2?rgh-link-date=2023-01-20T21%3A37%3A52Z)
14-
[![codecov](https://codecov.io/gh/open-feature/dotnet-sdk/branch/main/graph/badge.svg?token=MONAVJBXUJ)](https://codecov.io/gh/open-feature/dotnet-sdk)
15-
[![nuget](https://img.shields.io/nuget/vpre/OpenFeature)](https://www.nuget.org/packages/OpenFeature)
16-
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/6250/badge)](https://bestpractices.coreinfrastructure.org/projects/6250)
17-
18-
## 👋 Hey there! Thanks for checking out the OpenFeature .NET SDK
19-
20-
### What is OpenFeature?
13+
<!-- x-hide-in-docs-end -->
14+
<!-- The 'github-badges' class is used in the docs -->
15+
<p align="center" class="github-badges">
16+
<a href="https://github.com/open-feature/spec/tree/v0.6.0">
17+
<img alt="Specification" src="https://img.shields.io/static/v1?label=specification&message=v0.6.0&color=yellow&style=for-the-badge" />
18+
</a>
19+
<!-- x-release-please-start-version -->
20+
21+
<a href="https://github.com/open-feature/dotnet-sdk/releases/tag/v1.3.1">
22+
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v1.3.1&color=blue&style=for-the-badge" />
23+
</a>
24+
</a>
25+
<!-- x-release-please-end -->
26+
<br/>
27+
<a href="https://cloud-native.slack.com/archives/C0344AANLA1">
28+
<img alt="Slack" src="https://img.shields.io/badge/slack-%40cncf%2Fopenfeature-brightgreen?style=flat&logo=slack"/>
29+
</a>
30+
<a href="https://codecov.io/gh/open-feature/dotnet-sdk">
31+
<img alt="Codecov" src="https://codecov.io/gh/open-feature/dotnet-sdk/branch/main/graph/badge.svg?token=MONAVJBXUJ" />
32+
</a>
33+
<a href="https://www.nuget.org/packages/OpenFeature">
34+
<img alt="Codecov" src="https://img.shields.io/nuget/vpre/OpenFeature" />
35+
</a>
36+
<a href="https://www.bestpractices.dev/en/projects/6250">
37+
<img alt="CII Best Practices" src="https://bestpractices.coreinfrastructure.org/projects/6241/badge" />
38+
</a>
39+
</p>
40+
<!-- x-hide-in-docs-start -->
2141

22-
[OpenFeature][openfeature-website] is an open specification that provides a vendor-agnostic, community-driven API for feature flagging that works with your favorite feature flag management tool.
42+
[OpenFeature](https://openfeature.dev) is an open standard that provides a vendor-agnostic, community-driven API for feature flagging that works with your favorite feature flag management tool.
2343

24-
### Why standardize feature flags?
44+
<!-- x-hide-in-docs-end -->
2545

26-
Standardizing feature flags unifies tools and vendors behind a common interface which avoids vendor lock-in at the code level. Additionally, it offers a framework for building extensions and integrations and allows providers to focus on their unique value proposition.
46+
## 🚀 Quick start
2747

28-
## 🔍 Requirements:
48+
### Requirements
2949

30-
- .NET 6+
31-
- .NET Core 6+
32-
- .NET Framework 4.6.2+
50+
- .NET 6+
51+
- .NET Core 6+
52+
- .NET Framework 4.6.2+
3353

3454
Note that the packages will aim to support all current .NET versions. Refer to the currently supported versions [.NET](https://dotnet.microsoft.com/download/dotnet) and [.NET Framework](https://dotnet.microsoft.com/download/dotnet-framework) excluding .NET Framework 3.5
3555

36-
37-
## 📦 Installation:
56+
### Install
3857

3958
Use the following to initialize your project:
4059

@@ -48,106 +67,93 @@ and install OpenFeature:
4867
dotnet add package OpenFeature
4968
```
5069

51-
## 🌟 Features:
52-
53-
- support for various backend [providers](https://openfeature.dev/docs/reference/concepts/provider)
54-
- easy integration and extension via [hooks](https://openfeature.dev/docs/reference/concepts/hooks)
55-
- bool, string, numeric and object flag types
56-
- [context-aware](https://openfeature.dev/docs/reference/concepts/evaluation-context) evaluation
57-
58-
## 🚀 Usage:
59-
60-
### Basics:
70+
### Usage
6171

6272
```csharp
63-
using OpenFeature.Model;
64-
65-
// Sets the provider used by the client
66-
// If no provider is set, then a default NoOpProvider will be used.
67-
//OpenFeature.Api.Instance.SetProvider(new MyProvider());
68-
69-
// Gets a instance of the feature flag client
70-
var client = OpenFeature.Api.Instance.GetClient();
71-
// Evaluation the `my-feature` feature flag
72-
var isEnabled = await client.GetBooleanValue("my-feature", false);
73+
public async Task Example()
74+
{
75+
// Register your feature flag provider
76+
Api.Instance.SetProvider(new InMemoryProvider());
77+
78+
// Create a new client
79+
FeatureClient client = Api.Instance.GetClient();
80+
81+
// Evaluate your feature flag
82+
bool v2Enabled = await client.GetBooleanValue("v2_enabled", false);
83+
84+
if ( v2Enabled )
85+
{
86+
//Do some work
87+
}
88+
}
7389
```
7490

75-
For complete documentation, visit: https://openfeature.dev/docs/category/concepts
91+
## 🌟 Features
7692

77-
### Context-aware evaluation:
93+
| Status | Features | Description |
94+
| ------ | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
95+
|| [Providers](#providers) | Integrate with a commercial, open source, or in-house feature management tool. |
96+
|| [Targeting](#targeting) | Contextually-aware flag evaluation using [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context). |
97+
|| [Hooks](#hooks) | Add functionality to various stages of the flag evaluation life-cycle. |
98+
|| [Logging](#logging) | Integrate with popular logging packages. |
99+
|| [Named clients](#named-clients) | Utilize multiple providers in a single application. |
100+
|| [Eventing](#eventing) | React to state changes in the provider or flag management system. |
101+
|| [Shutdown](#shutdown) | Gracefully clean up a provider during application shutdown. |
102+
|| [Extending](#extending) | Extend OpenFeature with custom providers and hooks. |
78103

79-
Sometimes the value of a flag must take into account some dynamic criteria about the application or user, such as the user location, IP, email address, or the location of the server.
80-
In OpenFeature, we refer to this as [`targeting`](https://openfeature.dev/specification/glossary#targeting).
81-
If the flag system you're using supports targeting, you can provide the input data using the `EvaluationContext`.
104+
<sub>Implemented: ✅ | In-progress: ⚠️ | Not implemented yet: ❌</sub>
82105

83-
```csharp
84-
using OpenFeature.Model;
106+
### Providers
85107

86-
var client = OpenFeature.Api.Instance.GetClient();
87-
88-
// Evaluating with a context.
89-
var evaluationContext = EvaluationContext.Builder()
90-
.Set("my-key", "my-value")
91-
.Build();
92-
93-
// Evaluation the `my-conditional` feature flag
94-
var isEnabled = await client.GetBooleanValue("my-conditional", false, evaluationContext);
95-
```
108+
[Providers](https://openfeature.dev/docs/reference/concepts/provider) are an abstraction between a flag management system and the OpenFeature SDK.
109+
Look [here](https://openfeature.dev/docs/reference/technologies/server/dotnet/) for a complete list of available providers.
110+
If the provider you're looking for hasn't been created yet, see the [develop a provider](#develop-a-provider) section to learn how to build it yourself.
96111

97-
### Providers:
98-
99-
To develop a provider, you need to create a new project and include the OpenFeature SDK as a dependency. This can be a new repository or included in [the existing contrib repository](https://github.com/open-feature/dotnet-sdk-contrib) available under the OpenFeature organization. Finally, you’ll then need to write the provider itself. This can be accomplished by implementing the `FeatureProvider` interface exported by the OpenFeature SDK.
112+
Once you've added a provider as a dependency, it can be registered with OpenFeature like this:
100113

101114
```csharp
102-
using OpenFeature;
103-
using OpenFeature.Model;
104-
105-
public class MyFeatureProvider : FeatureProvider
106-
{
107-
public static string Name => "My Feature Provider";
108-
109-
public Metadata GetMetadata()
110-
{
111-
return new Metadata(Name);
112-
}
113-
114-
public Task<ResolutionDetails<bool>> ResolveBooleanValue(string flagKey, bool defaultValue,
115-
EvaluationContext context = null)
116-
{
117-
// code to resolve boolean details
118-
}
115+
Api.Instance.SetProvider(new MyProvider());
116+
```
119117

120-
public Task<ResolutionDetails<string>> ResolveStringValue(string flagKey, string defaultValue,
121-
EvaluationContext context = null)
122-
{
123-
// code to resolve string details
124-
}
118+
In some situations, it may be beneficial to register multiple providers in the same application.
119+
This is possible using [named clients](#named-clients), which is covered in more details below.
125120

126-
public Task<ResolutionDetails<int>> ResolveIntegerValue(string flagKey, int defaultValue,
127-
EvaluationContext context = null)
128-
{
129-
// code to resolve integer details
130-
}
121+
### Targeting
131122

132-
public Task<ResolutionDetails<double>> ResolveDoubleValue(string flagKey, double defaultValue,
133-
EvaluationContext context = null)
134-
{
135-
// code to resolve integer details
136-
}
123+
Sometimes, the value of a flag must consider some dynamic criteria about the application or user such as the user's location, IP, email address, or the server's location.
124+
In OpenFeature, we refer to this as [targeting](https://openfeature.dev/specification/glossary#targeting).
125+
If the flag management system you're using supports targeting, you can provide the input data using the [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context).
137126

138-
public Task<ResolutionDetails<T>> ResolveStructureValue<T>(string flagKey, T defaultValue,
139-
EvaluationContext context = null)
140-
{
141-
// code to resolve object details
142-
}
143-
}
127+
```csharp
128+
// set a value to the global context
129+
EvaluationContextBuilder builder = EvaluationContext.Builder();
130+
builder.Set("region", "us-east-1");
131+
EvaluationContext apiCtx = builder.Build();
132+
Api.Instance.SetContext(apiCtx);
133+
134+
// set a value to the client context
135+
builder = EvaluationContext.Builder();
136+
builder.Set("region", "us-east-1");
137+
EvaluationContext clientCtx = builder.Build();
138+
var client = Api.Instance.GetClient();
139+
client.SetContext(clientCtx);
140+
141+
142+
// set a value to the invocation context
143+
builder = EvaluationContext.Builder();
144+
builder.Set("region", "us-east-1");
145+
EvaluationContext reqCtx = builder.Build();
146+
147+
bool flagValue = await client.GetBooleanValue("some-flag", false, reqCtx);
144148
```
145149

146-
See [here](https://openfeature.dev/docs/reference/technologies/server/dotnet) for a catalog of available providers.
150+
### Hooks
147151

148-
### Hooks:
152+
[Hooks](https://openfeature.dev/docs/reference/concepts/hooks) allow for custom logic to be added at well-defined points of the flag evaluation life-cycle.
153+
Look [here](https://openfeature.dev/docs/reference/technologies/server/dotnet/) for a complete list of available hooks.
154+
If the hook you're looking for hasn't been created yet, see the [develop a hook](#develop-a-hook) section to learn how to build it yourself.
149155

150-
Hooks are a mechanism that allow for the addition of arbitrary behavior at well-defined points of the flag evaluation life-cycle. Use cases include validation of the resolved flag value, modifying or adding data to the evaluation context, logging, telemetry, and tracking.
156+
Once you've added a hook as a dependency, it can be registered at the global, client, or flag invocation level.
151157

152158
```csharp
153159
// add a hook globally, to run on all evaluations
@@ -161,7 +167,77 @@ client.AddHooks(new ExampleClientHook());
161167
var value = await client.GetBooleanValue("boolFlag", false, context, new FlagEvaluationOptions(new ExampleInvocationHook()));
162168
```
163169

164-
Example of implementing a hook
170+
### Logging
171+
172+
The .NET SDK uses Microsoft Extensions Logger. See the [manual](https://learn.microsoft.com/en-us/dotnet/core/extensions/logging?tabs=command-line) for complete documentation.
173+
174+
### Named clients
175+
176+
Clients can be given a name.
177+
A name is a logical identifier which can be used to associate clients with a particular provider.
178+
If a name has no associated provider, the global provider is used.
179+
180+
```csharp
181+
// registering the default provider
182+
Api.Instance.SetProvider(new LocalProvider());
183+
// registering a named provider
184+
Api.Instance.SetProvider("clientForCache", new CachedProvider());
185+
186+
// a client backed by default provider
187+
FeatureClient clientDefault = Api.Instance.GetClient();
188+
// a client backed by CachedProvider
189+
FeatureClient clientNamed = Api.Instance.GetClient("clientForCache");
190+
```
191+
192+
## Extending
193+
194+
### Develop a provider
195+
196+
To develop a provider, you need to create a new project and include the OpenFeature SDK as a dependency.
197+
This can be a new repository or included in [the existing contrib repository](https://github.com/open-feature/dotnet-sdk) available under the OpenFeature organization.
198+
You’ll then need to write the provider by implementing the `FeatureProvider` interface exported by the OpenFeature SDK.
199+
200+
```csharp
201+
public class MyProvider : FeatureProvider
202+
{
203+
public override Metadata GetMetadata()
204+
{
205+
return new Metadata("My Provider");
206+
}
207+
208+
public override Task<ResolutionDetails<bool>> ResolveBooleanValue(string flagKey, bool defaultValue, EvaluationContext context = null)
209+
{
210+
// resolve a boolean flag value
211+
}
212+
213+
public override Task<ResolutionDetails<double>> ResolveDoubleValue(string flagKey, double defaultValue, EvaluationContext context = null)
214+
{
215+
// resolve a double flag value
216+
}
217+
218+
public override Task<ResolutionDetails<int>> ResolveIntegerValue(string flagKey, int defaultValue, EvaluationContext context = null)
219+
{
220+
// resolve an int flag value
221+
}
222+
223+
public override Task<ResolutionDetails<string>> ResolveStringValue(string flagKey, string defaultValue, EvaluationContext context = null)
224+
{
225+
// resolve a string flag value
226+
}
227+
228+
public override Task<ResolutionDetails<Value>> ResolveStructureValue(string flagKey, Value defaultValue, EvaluationContext context = null)
229+
{
230+
// resolve an object flag value
231+
}
232+
}
233+
```
234+
235+
### Develop a hook
236+
237+
To develop a hook, you need to create a new project and include the OpenFeature SDK as a dependency.
238+
This can be a new repository or included in [the existing contrib repository](https://github.com/open-feature/dotnet-sdk) available under the OpenFeature organization.
239+
Implement your own hook by conforming to the `Hook interface`.
240+
To satisfy the interface, all methods (`Before`/`After`/`Finally`/`Error`) need to be defined.
165241

166242
```csharp
167243
public class MyHook : Hook
@@ -191,20 +267,16 @@ public class MyHook : Hook
191267
}
192268
```
193269

194-
See [here](https://openfeature.dev/docs/reference/technologies/server/dotnet) for a catalog of available hooks.
195-
196-
### Logging:
197-
198-
The .NET SDK uses Microsoft Extensions Logger. See the [manual](https://learn.microsoft.com/en-us/dotnet/core/extensions/logging?tabs=command-line) for complete documentation.
270+
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!
199271

200272
## ⭐️ Support the project
201273

202-
- Give this repo a ⭐️!
203-
- Follow us social media:
204-
- Twitter: [@openfeature](https://twitter.com/openfeature)
205-
- LinkedIn: [OpenFeature](https://www.linkedin.com/company/openfeature/)
206-
- Join us on [Slack](https://cloud-native.slack.com/archives/C0344AANLA1)
207-
- For more check out our [community page](https://openfeature.dev/community/)
274+
- Give this repo a ⭐️!
275+
- Follow us social media:
276+
- Twitter: [@openfeature](https://twitter.com/openfeature)
277+
- LinkedIn: [OpenFeature](https://www.linkedin.com/company/openfeature/)
278+
- Join us on [Slack](https://cloud-native.slack.com/archives/C0344AANLA1)
279+
- For more check out our [community page](https://openfeature.dev/community/)
208280

209281
## 🤝 Contributing
210282

Diff for: release-please-config.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
"bump-patch-for-minor-pre-major": true,
99
"versioning": "default",
1010
"extra-files": [
11-
"build/Common.prod.props"
11+
"build/Common.prod.props",
12+
"README.md"
1213
]
1314
}
1415
},

0 commit comments

Comments
 (0)