Skip to content

Commit

Permalink
Merge branch 'main' into central-package-management
Browse files Browse the repository at this point in the history
  • Loading branch information
askpt authored Jan 19, 2024
2 parents bcd4c4c + 18a092a commit c474de8
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 32 deletions.
54 changes: 25 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,31 @@ client.AddHooks(new ExampleClientHook());
var value = await client.GetBooleanValue("boolFlag", false, context, new FlagEvaluationOptions(new ExampleInvocationHook()));
```

### Logging

The .NET SDK uses Microsoft.Extensions.Logging. See the [manual](https://learn.microsoft.com/en-us/dotnet/core/extensions/logging?tabs=command-line) for complete documentation.

### Named clients

Clients can be given a name.
A name is a logical identifier that can be used to associate clients with a particular provider.
If a name has no associated provider, the global provider is used.

```csharp
// registering the default provider
await Api.Instance.SetProvider(new LocalProvider());

// registering a named provider
await Api.Instance.SetProvider("clientForCache", new CachedProvider());

// a client backed by default provider
FeatureClient clientDefault = Api.Instance.GetClient();

// a client backed by CachedProvider
FeatureClient clientNamed = Api.Instance.GetClient("clientForCache");

```

### Eventing

Events allow you to react to state changes in the provider or underlying flag management system, such as flag definition changes,
Expand Down Expand Up @@ -204,35 +229,6 @@ await Api.Instance.SetProvider(myClient.GetMetadata().Name, provider);
myClient.AddHandler(ProviderEventTypes.ProviderReady, callback);
```

### Logging

The .NET SDK uses Microsoft.Extensions.Logging. See the [manual](https://learn.microsoft.com/en-us/dotnet/core/extensions/logging?tabs=command-line) for complete documentation.

### Named clients

Clients can be given a name.
A name is a logical identifier that can be used to associate clients with a particular provider.
If a name has no associated provider, the global provider is used.

```csharp
// registering the default provider
await Api.Instance.SetProvider(new LocalProvider());

// registering a named provider
await Api.Instance.SetProvider("clientForCache", new CachedProvider());

// a client backed by default provider
FeatureClient clientDefault = Api.Instance.GetClient();

// a client backed by CachedProvider
FeatureClient clientNamed = Api.Instance.GetClient("clientForCache");

```

### Eventing

Events are currently not supported by the .NET SDK. Progress on this feature can be tracked [here](https://github.com/open-feature/dotnet-sdk/issues/126).

### Shutdown

The OpenFeature API provides a close function to perform a cleanup of all registered providers. This should only be called when your application is in the process of shutting down.
Expand Down
21 changes: 20 additions & 1 deletion src/OpenFeature/Api.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,26 @@ public FeatureClient GetClient(string name = null, string version = null, ILogge
/// </para>
/// </summary>
/// <param name="hooks">A list of <see cref="Hook"/></param>
public void AddHooks(IEnumerable<Hook> hooks) => this._hooks.PushRange(hooks.ToArray());
public void AddHooks(IEnumerable<Hook> hooks)
#if NET7_0_OR_GREATER
=> this._hooks.PushRange(hooks as Hook[] ?? hooks.ToArray());
#else
{
// See: https://github.com/dotnet/runtime/issues/62121
if (hooks is Hook[] array)
{
if (array.Length > 0)
this._hooks.PushRange(array);

return;
}

array = hooks.ToArray();

if (array.Length > 0)
this._hooks.PushRange(array);
}
#endif

/// <summary>
/// Adds a hook to global hooks list
Expand Down
2 changes: 1 addition & 1 deletion src/OpenFeature/FeatureProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public abstract class FeatureProvider
/// <summary>
/// The event channel of the provider.
/// </summary>
protected Channel<object> EventChannel = Channel.CreateBounded<object>(1);
protected readonly Channel<object> EventChannel = Channel.CreateBounded<object>(1);

/// <summary>
/// Metadata describing the provider.
Expand Down
21 changes: 20 additions & 1 deletion src/OpenFeature/OpenFeatureClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,26 @@ public void RemoveHandler(ProviderEventTypes type, EventHandlerDelegate handler)
}

/// <inheritdoc />
public void AddHooks(IEnumerable<Hook> hooks) => this._hooks.PushRange(hooks.ToArray());
public void AddHooks(IEnumerable<Hook> hooks)
#if NET7_0_OR_GREATER
=> this._hooks.PushRange(hooks as Hook[] ?? hooks.ToArray());
#else
{
// See: https://github.com/dotnet/runtime/issues/62121
if (hooks is Hook[] array)
{
if (array.Length > 0)
this._hooks.PushRange(array);

return;
}

array = hooks.ToArray();

if (array.Length > 0)
this._hooks.PushRange(array);
}
#endif

/// <inheritdoc />
public IEnumerable<Hook> GetHooks() => this._hooks.Reverse();
Expand Down
7 changes: 7 additions & 0 deletions test/OpenFeature.Tests/OpenFeatureHookTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -553,5 +553,12 @@ public async Task When_Error_Occurs_In_After_Hook_Should_Invoke_Error_Hook()

await featureProvider.DidNotReceive().ResolveBooleanValue("test", false, Arg.Any<EvaluationContext>());
}

[Fact]
public void Add_hooks_should_accept_empty_enumerable()
{
Api.Instance.ClearHooks();
Api.Instance.AddHooks(Enumerable.Empty<Hook>());
}
}
}

0 comments on commit c474de8

Please sign in to comment.