-
Notifications
You must be signed in to change notification settings - Fork 127
Feature-based Injection #335
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
Merged
zhiyuanliang-ms
merged 31 commits into
preview
from
zhiyuanliang/feature-based-injection
Feb 9, 2024
Merged
Changes from 15 commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
57d2243
init
zhiyuanliang-ms f9506c9
draft
zhiyuanliang-ms f9c1484
Merge branch 'preview' into zhiyuanliang/feature-based-injection
zhiyuanliang-ms 5edd9be
use ValueTask
zhiyuanliang-ms 06f410b
Merge branch 'preview' of https://github.com/microsoft/FeatureManagem…
zhiyuanliang-ms e1b2450
support factory method
zhiyuanliang-ms f497405
add example
zhiyuanliang-ms 2b7ad46
Merge branch 'preview' of https://github.com/microsoft/FeatureManagem…
zhiyuanliang-ms d89abc8
update
zhiyuanliang-ms ca772ec
Update
zhiyuanliang-ms 3710dab
Merge branch 'preview' into zhiyuanliang/feature-based-injection
zhiyuanliang-ms b92fefb
Update
zhiyuanliang-ms f3926f8
update example
zhiyuanliang-ms 0d0f3f3
match variant name or configuration value
zhiyuanliang-ms 176cf78
update to the latest design
zhiyuanliang-ms a7b8f0f
merge with preview branch
zhiyuanliang-ms 73aac10
resolve comments
zhiyuanliang-ms 25f91e9
remove check for variant value
zhiyuanliang-ms 3ed4c4c
rename to VariantService
zhiyuanliang-ms 941c7a1
update & add comments
zhiyuanliang-ms 18ae0eb
remove POC example
zhiyuanliang-ms f48767c
add testcases & use method name GetServiceAsync
zhiyuanliang-ms 1556c0d
update comments
zhiyuanliang-ms 7120abd
add variant service cache
zhiyuanliang-ms 1a4e0fa
resolve comments
zhiyuanliang-ms 926182a
throw exception for duplicated registration
zhiyuanliang-ms 1065d76
add testcase
zhiyuanliang-ms 37cda1b
remove unused package
zhiyuanliang-ms df47105
update comment
zhiyuanliang-ms cbda0c6
set feature name in constructor
zhiyuanliang-ms 6488a81
Merge branch 'preview' into zhiyuanliang/feature-based-injection
zhiyuanliang-ms File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| namespace FeatureBasedInjectionPOC | ||
| { | ||
| internal class AlgorithmAlpha : IAlgorithm | ||
| { | ||
| public string Name { get; set; } | ||
|
|
||
| public AlgorithmAlpha() | ||
| { | ||
| Name = "Alpha"; | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| namespace FeatureBasedInjectionPOC | ||
| { | ||
| internal class AlgorithmBeta : IAlgorithm | ||
| { | ||
| public string Name { get; set; } | ||
|
|
||
| public AlgorithmBeta() | ||
| { | ||
| Name = "Beta"; | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| using Microsoft.FeatureManagement; | ||
|
|
||
| namespace FeatureBasedInjectionPOC | ||
| { | ||
| [FeaturedServiceAlias("Omega")] | ||
| class AlgorithmOmega : IAlgorithm | ||
| { | ||
| public string Name { get; set; } | ||
|
|
||
| public AlgorithmOmega(string name) | ||
| { | ||
| Name = name; | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| namespace FeatureBasedInjectionPOC | ||
| { | ||
| internal class AlgorithmSigma : IAlgorithm | ||
| { | ||
| public string Name { get; set; } | ||
|
|
||
| public AlgorithmSigma() | ||
| { | ||
| Name = "Sigma"; | ||
| } | ||
| } | ||
| } |
25 changes: 25 additions & 0 deletions
25
examples/FeatureBasedInjectionPOC/FeatureBasedInjectionPOC.csproj
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <OutputType>Exe</OutputType> | ||
| <TargetFramework>net6.0</TargetFramework> | ||
| <ImplicitUsings>enable</ImplicitUsings> | ||
| <Nullable>enable</Nullable> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup> | ||
| <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" /> | ||
| <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" /> | ||
| </ItemGroup> | ||
|
|
||
| <ItemGroup> | ||
| <ProjectReference Include="..\..\src\Microsoft.FeatureManagement\Microsoft.FeatureManagement.csproj" /> | ||
| </ItemGroup> | ||
|
|
||
| <ItemGroup> | ||
| <None Update="appsettings.json"> | ||
| <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||
| </None> | ||
| </ItemGroup> | ||
|
|
||
| </Project> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| namespace FeatureBasedInjectionPOC | ||
| { | ||
| public interface IAlgorithm | ||
| { | ||
| public string Name { get; } | ||
| } | ||
| } | ||
14 changes: 14 additions & 0 deletions
14
examples/FeatureBasedInjectionPOC/OnDemandTargetingContextAccessor.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| using Microsoft.FeatureManagement.FeatureFilters; | ||
|
|
||
| namespace FeatureBasedInjectionPOC | ||
| { | ||
| class OnDemandTargetingContextAccessor : ITargetingContextAccessor | ||
| { | ||
| public TargetingContext Current { get; set; } | ||
|
|
||
| public ValueTask<TargetingContext> GetContextAsync() | ||
| { | ||
| return new ValueTask<TargetingContext>(Current); | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| using Microsoft.Extensions.Configuration; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
| using Microsoft.FeatureManagement; | ||
| using Microsoft.FeatureManagement.FeatureFilters; | ||
| using FeatureBasedInjectionPOC; | ||
|
|
||
|
|
||
| IConfiguration configuration = new ConfigurationBuilder() | ||
| .AddJsonFile("appsettings.json") | ||
| .Build(); | ||
|
|
||
| IServiceCollection services = new ServiceCollection(); | ||
|
|
||
| services.AddSingleton<IAlgorithm, AlgorithmAlpha>(); | ||
| services.AddSingleton<IAlgorithm, AlgorithmBeta>(); | ||
| services.AddSingleton<IAlgorithm, AlgorithmSigma>(); | ||
| services.AddSingleton<IAlgorithm>(sp => new AlgorithmOmega("Omega")); | ||
|
|
||
| services.AddSingleton(configuration) | ||
| .AddFeatureManagement() | ||
| .AddFeatureFilter<TargetingFilter>() | ||
| .AddFeaturedService<IAlgorithm>("MyFeature"); | ||
|
|
||
| var targetingContextAccessor = new OnDemandTargetingContextAccessor(); | ||
|
|
||
| services.AddSingleton<ITargetingContextAccessor>(targetingContextAccessor); | ||
|
|
||
| using (ServiceProvider serviceProvider = services.BuildServiceProvider()) | ||
| { | ||
| IVariantFeatureManager featureManager = serviceProvider.GetRequiredService<IVariantFeatureManager>(); | ||
|
|
||
| IFeaturedService<IAlgorithm> featuredAlgorithm = serviceProvider.GetRequiredService<IFeaturedService<IAlgorithm>>(); | ||
|
|
||
| targetingContextAccessor.Current = new TargetingContext | ||
| { | ||
| UserId = "Guest" | ||
| }; | ||
|
|
||
| IAlgorithm algorithm = await featuredAlgorithm.GetAsync(CancellationToken.None); | ||
|
|
||
| Variant variant = await featureManager.GetVariantAsync("MyFeature", CancellationToken.None); | ||
|
|
||
| Console.WriteLine($"Get algorithm {algorithm?.Name ?? "Null"} because the feature variant is {variant?.Name ?? "Null"}"); | ||
|
|
||
| targetingContextAccessor.Current = new TargetingContext | ||
| { | ||
| UserId = "UserBeta" | ||
| }; | ||
|
|
||
| algorithm = await featuredAlgorithm.GetAsync(CancellationToken.None); | ||
|
|
||
| variant = await featureManager.GetVariantAsync("MyFeature", CancellationToken.None); | ||
|
|
||
| Console.WriteLine($"Get algorithm {algorithm?.Name ?? "Null"} because the feature variant is {variant?.Name ?? "Null"}"); | ||
|
|
||
| targetingContextAccessor.Current = new TargetingContext | ||
| { | ||
| UserId = "UserSigma" | ||
| }; | ||
|
|
||
| algorithm = await featuredAlgorithm.GetAsync(CancellationToken.None); | ||
|
|
||
| variant = await featureManager.GetVariantAsync("MyFeature", CancellationToken.None); | ||
|
|
||
| Console.WriteLine($"Get algorithm {algorithm?.Name ?? "Null"} because the feature variant is {variant?.Name ?? "Null"}"); | ||
|
|
||
| targetingContextAccessor.Current = new TargetingContext | ||
| { | ||
| UserId = "UserOmega" | ||
| }; | ||
|
|
||
| algorithm = await featuredAlgorithm.GetAsync(CancellationToken.None); | ||
|
|
||
| variant = await featureManager.GetVariantAsync("MyFeature", CancellationToken.None); | ||
|
|
||
| Console.WriteLine($"Get algorithm {algorithm?.Name ?? "Null"} because the feature variant is {variant?.Name ?? "Null"}"); | ||
|
zhiyuanliang-ms marked this conversation as resolved.
Outdated
|
||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| { | ||
| "FeatureManagement": { | ||
| "MyFeature": { | ||
| "EnabledFor": [ | ||
| { | ||
| "Name": "Targeting", | ||
| "Parameters": { | ||
| "Audience": { | ||
| "Users": [ | ||
| "UserOmega", "UserSigma", "UserBeta" | ||
| ] | ||
| } | ||
| } | ||
| } | ||
| ], | ||
| "Variants": [ | ||
| { | ||
| "Name": "AlgorithmBeta" | ||
| }, | ||
| { | ||
| "Name": "Sigma", | ||
| "ConfigurationValue": "AlgorithmSigma" | ||
| }, | ||
| { | ||
| "Name": "Omega" | ||
| } | ||
| ], | ||
| "Allocation": { | ||
| "User": [ | ||
| { | ||
| "Variant": "AlgorithmBeta", | ||
| "Users": [ | ||
| "UserBeta" | ||
| ] | ||
| }, | ||
| { | ||
| "Variant": "Omega", | ||
| "Users": [ | ||
| "UserOmega" | ||
| ] | ||
| }, | ||
| { | ||
| "Variant": "Sigma", | ||
| "Users": [ | ||
| "UserSigma" | ||
| ] | ||
| } | ||
| ] | ||
| } | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT license. | ||
| // | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Diagnostics; | ||
| using System.Linq; | ||
| using System.Threading; | ||
| using System.Threading.Tasks; | ||
|
|
||
| namespace Microsoft.FeatureManagement | ||
| { | ||
| internal class FeaturedService<TService> : IFeaturedService<TService> where TService : class | ||
| { | ||
| private readonly string _featureName; | ||
| private readonly IVariantFeatureManager _featureManager; | ||
| private readonly IEnumerable<TService> _services; | ||
|
|
||
| public FeaturedService(string featureName, IEnumerable<TService> services, IVariantFeatureManager featureManager) | ||
| { | ||
| _featureName = featureName; | ||
| _services = services; | ||
| _featureManager = featureManager; | ||
| } | ||
|
|
||
| public async ValueTask<TService> GetAsync(CancellationToken cancellationToken) | ||
| { | ||
| Variant variant = await _featureManager.GetVariantAsync(_featureName, cancellationToken); | ||
|
|
||
| TService implementation = null; | ||
|
|
||
| if (variant != null) | ||
| { | ||
| implementation = _services.FirstOrDefault(service => | ||
| IsMatchingVariant( | ||
| service.GetType(), | ||
| variant)); | ||
| } | ||
|
|
||
| return implementation; | ||
| } | ||
|
|
||
| private bool IsMatchingVariant(Type implementationType, Variant variant) | ||
| { | ||
| Debug.Assert(variant != null); | ||
|
|
||
| string implementationName = ((FeaturedServiceAliasAttribute)Attribute.GetCustomAttribute(implementationType, typeof(FeaturedServiceAliasAttribute)))?.Alias; | ||
|
|
||
| if (implementationName == null) | ||
| { | ||
| implementationName = implementationType.Name; | ||
| } | ||
|
|
||
| string variantConfiguration = variant.Configuration?.Value; | ||
|
zhiyuanliang-ms marked this conversation as resolved.
Outdated
|
||
|
|
||
| if (variantConfiguration != null && string.Equals(implementationName, variantConfiguration, StringComparison.OrdinalIgnoreCase)) | ||
| { | ||
| return true; | ||
| } | ||
|
|
||
| return string.Equals(implementationName, variant.Name, StringComparison.OrdinalIgnoreCase); | ||
| } | ||
| } | ||
| } | ||
22 changes: 22 additions & 0 deletions
22
src/Microsoft.FeatureManagement/FeaturedServiceAliasAttribute.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT license. | ||
| // | ||
| using System; | ||
|
|
||
| namespace Microsoft.FeatureManagement | ||
| { | ||
| public class FeaturedServiceAliasAttribute : Attribute | ||
| { | ||
| public FeaturedServiceAliasAttribute(string alias) | ||
| { | ||
| if (string.IsNullOrEmpty(alias)) | ||
| { | ||
| throw new ArgumentNullException(nameof(alias)); | ||
| } | ||
|
|
||
| Alias = alias; | ||
| } | ||
|
|
||
| public string Alias { get; } | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.