Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
ef0bfd4
Working allocationId
rossgrambo Sep 10, 2024
27330d7
Adds Base64Url byte extension, adjusts TelemetryEventHandler logic, a…
rossgrambo Sep 11, 2024
ba1676c
Update comments
rossgrambo Sep 11, 2024
ada8823
Removed allocation id and fixed some tests
rossgrambo Sep 13, 2024
85cdd0a
Removed bytes extension
rossgrambo Sep 16, 2024
f9cb776
Merge branch 'preview' into rossgrambo-extra-telemetry-fields
rossgrambo Oct 22, 2024
9406999
Update src/Microsoft.FeatureManagement/Telemetry/TelemetryEventHandle…
rossgrambo Oct 23, 2024
e53aeb0
Resolving comments
rossgrambo Oct 23, 2024
a904411
Merge branch 'rossgrambo-extra-telemetry-fields' of https://github.co…
rossgrambo Oct 23, 2024
4cb6a17
Fix formatting
rossgrambo Oct 23, 2024
ec5415f
Merge pull request #495 from microsoft/rossgrambo-extra-telemetry-fields
rossgrambo Oct 23, 2024
98a682d
Version Bump
rossgrambo Oct 23, 2024
22ce7b2
Merge pull request #510 from microsoft/rossgrambo/version-bump-v4-pre…
rossgrambo Oct 23, 2024
de3c346
Merge pull request #509 from microsoft/main
rossgrambo Oct 23, 2024
b830f09
Create codeql.yml
mrm9084 Nov 1, 2024
4615186
Merge pull request #516 from microsoft/mrm9084-patch-1
mrm9084 Nov 1, 2024
57c8f24
use cookie auth in variant service example (#518)
zhiyuanliang-ms Dec 4, 2024
325271b
Negate FeatureGateAttribute (#519)
zhiyuanliang-ms Dec 11, 2024
76969fa
Add testcases for time window filter cache entry (#445)
zhiyuanliang-ms Dec 17, 2024
9a4dd65
drop net 6 (#526)
zhiyuanliang-ms Jan 20, 2025
71aa5f2
Avoid using boolean.ToString and enum.ToString (#525)
zhiyuanliang-ms Jan 21, 2025
87d2500
Small fix for recurring time window testcase (#522)
zhiyuanliang-ms Jan 22, 2025
d310978
add feature flags support for endpoints
crodriguesbr Dec 30, 2024
cafde19
update documentation for endpoint feature flags support and add tests…
crodriguesbr Dec 30, 2024
be2befd
remove predicate parameter and add ambient context for targeting
crodriguesbr Jan 3, 2025
4675111
rename API to WithFeatureGate and drop .NET 6 support
crodriguesbr Jan 15, 2025
6be4791
adjust code style for compliance with coding standards
crodriguesbr Jan 16, 2025
00be8e7
Refactor feature management code:
crodriguesbr Jan 16, 2025
e387529
Add license header to source files
crodriguesbr Jan 17, 2025
76e1c41
rename files and remove unused libraries
crodriguesbr Jan 22, 2025
78b1f9a
add support for multiple features evaluation
crodriguesbr Jan 27, 2025
e033a75
update FeatureGateEndpointFilter for flexibility and consistency
crodriguesbr Feb 7, 2025
d17365b
change featuregateendpointfilter class to internal
crodriguesbr Feb 7, 2025
e4e29e1
refactor featuregateendpointfilter for improved encapsulation
crodriguesbr Feb 7, 2025
8708158
Merge pull request #524 from crodriguesbr/add-feature-flags-endpoint-…
jimmyca15 Feb 7, 2025
aeed650
Do not use DI for console app example (#528)
zhiyuanliang-ms Feb 10, 2025
fa0e457
fix lint (#530)
zhiyuanliang-ms Feb 17, 2025
24bcf7b
Adds cancellationtoken to the FeatureEvaluationContext- and respects …
rossgrambo Mar 28, 2025
baf7664
Fixed broken link to JSON schema in MicrosoftFeatureManagementFields.cs
abatishchev May 6, 2025
9c84875
Merge pull request #533 from abatishchev/patch-1
jimmyca15 May 6, 2025
20c12d2
Resolving comments
rossgrambo May 8, 2025
5e4efbb
Merge branch 'main' into rossgrambo/cancellationToken
rossgrambo May 9, 2025
f2c258b
Merge pull request #532 from microsoft/rossgrambo/cancellationToken
rossgrambo May 9, 2025
58ae781
Add gitattributes (#538)
amerjusupovic May 19, 2025
77fee5d
merge preview
zhiyuanliang-ms May 20, 2025
b5fd2d0
Merge preview to main (#539)
zhiyuanliang-ms May 20, 2025
139296d
version bump 4.1.0 (#540)
zhiyuanliang-ms May 20, 2025
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
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# If there are abnormal line endings in any file, run "git add --renormalize <file_name>",
# review the changes, and commit them to fix the line endings.
* text=auto
92 changes: 92 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL Advanced"

on:
push:
branches: [ "main", "preview", "release/*" ]
pull_request:
branches: [ "main", "preview", "release/*" ]
schedule:
- cron: '21 11 * * 3'

jobs:
analyze:
name: Analyze (${{ matrix.language }})
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners (GitHub.com only)
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
permissions:
# required for all workflows
security-events: write

# required to fetch internal or private CodeQL packs
packages: read

# only required for workflows in private repositories
actions: read
contents: read

strategy:
fail-fast: false
matrix:
include:
- language: csharp
build-mode: none
# CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- name: Checkout repository
uses: actions/checkout@v4

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.

# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality

# If the analyze step fails for one of the languages you are analyzing with
# "We were unable to automatically build your code", modify the matrix above
# to set the build mode to "manual" for that language. Then modify this step
# to build your code.
# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- if: matrix.build-mode == 'manual'
shell: bash
run: |
echo 'If you are using a "manual" build mode for one or more of the' \
'languages you are analyzing, replace this with the commands to build' \
'your code, for example:'
echo ' make bootstrap'
echo ' make release'
exit 1

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
42 changes: 21 additions & 21 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
MIT License
Copyright (c) Microsoft Corporation. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
MIT License

Copyright (c) Microsoft Corporation. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE
76 changes: 38 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@
# .NET Feature Management
[![Microsoft.FeatureManagement](https://img.shields.io/nuget/v/Microsoft.FeatureManagement?label=Microsoft.FeatureManagement)](https://www.nuget.org/packages/Microsoft.FeatureManagement)
[![Microsoft.FeatureManagement.AspNetCore](https://img.shields.io/nuget/v/Microsoft.FeatureManagement.AspNetCore?label=Microsoft.FeatureManagement.AspNetCore)](https://www.nuget.org/packages/Microsoft.FeatureManagement.AspNetCore)
Feature management provides a way to develop and expose application functionality based on features. Many applications have special requirements when a new feature is developed such as when the feature should be enabled and under what conditions. This library provides a way to define these relationships, and also integrates into common .NET code patterns to make exposing these features possible.
## Get started
[**Quickstart**](https://learn.microsoft.com/azure/azure-app-configuration/quickstart-feature-flag-dotnet): A quickstart guide is available to learn how to integrate feature flags from *Azure App Configuration* into your .NET applications.
[**Feature Reference**](https://learn.microsoft.com/azure/azure-app-configuration/feature-management-dotnet-reference): This document provides a full feature rundown.
[**API reference**](https://go.microsoft.com/fwlink/?linkid=2091700): This API reference details the API surface of the libraries contained within this repository.
## Examples
* [.NET Console App](./examples/ConsoleApp)
* [.NET Console App with Targeting](./examples/TargetingConsoleApp)
* [ASP.NET Core Web App (Razor Page)](./examples/RazorPages)
* [ASP.NET Core Web App (MVC)](./examples/FeatureFlagDemo)
* [Blazor Server App](./examples/BlazorServerApp)
* [ASP.NET Core Web App with Variants and Telemetry](./examples/VariantAndTelemetryDemo)
* [ASP.NET Core Web App with Variant Service](./examples/VariantServiceDemo)
## Contributing
This project welcomes contributions and suggestions. Most contributions require you to agree to a
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
the rights to use your contribution. For details, visit https://cla.microsoft.com.
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
provided by the bot. You will only need to do this once across all repos using our CLA.
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
# .NET Feature Management

[![Microsoft.FeatureManagement](https://img.shields.io/nuget/v/Microsoft.FeatureManagement?label=Microsoft.FeatureManagement)](https://www.nuget.org/packages/Microsoft.FeatureManagement)
[![Microsoft.FeatureManagement.AspNetCore](https://img.shields.io/nuget/v/Microsoft.FeatureManagement.AspNetCore?label=Microsoft.FeatureManagement.AspNetCore)](https://www.nuget.org/packages/Microsoft.FeatureManagement.AspNetCore)

Feature management provides a way to develop and expose application functionality based on features. Many applications have special requirements when a new feature is developed such as when the feature should be enabled and under what conditions. This library provides a way to define these relationships, and also integrates into common .NET code patterns to make exposing these features possible.

## Get started

[**Quickstart**](https://learn.microsoft.com/azure/azure-app-configuration/quickstart-feature-flag-dotnet): A quickstart guide is available to learn how to integrate feature flags from *Azure App Configuration* into your .NET applications.

[**Feature Reference**](https://learn.microsoft.com/azure/azure-app-configuration/feature-management-dotnet-reference): This document provides a full feature rundown.

[**API reference**](https://go.microsoft.com/fwlink/?linkid=2091700): This API reference details the API surface of the libraries contained within this repository.

## Examples

* [.NET Console App](./examples/ConsoleApp)
* [.NET Console App with Targeting](./examples/TargetingConsoleApp)
* [ASP.NET Core Web App (Razor Page)](./examples/RazorPages)
* [ASP.NET Core Web App (MVC)](./examples/FeatureFlagDemo)
* [Blazor Server App](./examples/BlazorServerApp)
* [ASP.NET Core Web App with Variants and Telemetry](./examples/VariantAndTelemetryDemo)
* [ASP.NET Core Web App with Variant Service](./examples/VariantServiceDemo)

## Contributing

This project welcomes contributions and suggestions. Most contributions require you to agree to a
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
the rights to use your contribution. For details, visit https://cla.microsoft.com.

When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
provided by the bot. You will only need to do this once across all repos using our CLA.

This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
6 changes: 1 addition & 5 deletions build/install-dotnet.ps1
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
# Installs .NET 6, .NET 7 and .NET 8 for CI/CD environment
# Installs .NET 8 and .NET 9 for CI/CD environment
# see: https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-install-script#examples

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;

&([scriptblock]::Create((Invoke-WebRequest -UseBasicParsing 'https://dot.net/v1/dotnet-install.ps1'))) -Channel 6.0

&([scriptblock]::Create((Invoke-WebRequest -UseBasicParsing 'https://dot.net/v1/dotnet-install.ps1'))) -Channel 7.0

&([scriptblock]::Create((Invoke-WebRequest -UseBasicParsing 'https://dot.net/v1/dotnet-install.ps1'))) -Channel 8.0

&([scriptblock]::Create((Invoke-WebRequest -UseBasicParsing 'https://dot.net/v1/dotnet-install.ps1'))) -Channel 9.0
55 changes: 22 additions & 33 deletions examples/ConsoleApp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Licensed under the MIT license.
//
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.FeatureManagement;

//
Expand All @@ -11,45 +10,35 @@
.AddJsonFile("appsettings.json")
.Build();

//
// Setup application services + feature management
IServiceCollection services = new ServiceCollection();
var featureManager = new FeatureManager(new ConfigurationFeatureDefinitionProvider(configuration))
{
FeatureFilters = new List<IFeatureFilterMetadata> { new AccountIdFilter() }
};

services.AddSingleton(configuration)
.AddFeatureManagement()
.AddFeatureFilter<AccountIdFilter>();
var accounts = new List<string>()
{
"abc",
"adef",
"abcdefghijklmnopqrstuvwxyz"
};

//
// Get the feature manager from application services
using (ServiceProvider serviceProvider = services.BuildServiceProvider())
// Mimic work items in a task-driven console application
foreach (var account in accounts)
{
IFeatureManager featureManager = serviceProvider.GetRequiredService<IFeatureManager>();

var accounts = new List<string>()
{
"abc",
"adef",
"abcdefghijklmnopqrstuvwxyz"
};
const string FeatureName = "Beta";

//
// Mimic work items in a task-driven console application
foreach (var account in accounts)
// Check if feature enabled
//
var accountServiceContext = new AccountServiceContext
{
const string FeatureName = "Beta";

//
// Check if feature enabled
//
var accountServiceContext = new AccountServiceContext
{
AccountId = account
};
AccountId = account
};

bool enabled = await featureManager.IsEnabledAsync(FeatureName, accountServiceContext);
bool enabled = await featureManager.IsEnabledAsync(FeatureName, accountServiceContext);

//
// Output results
Console.WriteLine($"The {FeatureName} feature is {(enabled ? "enabled" : "disabled")} for the '{account}' account.");
}
//
// Output results
Console.WriteLine($"The {FeatureName} feature is {(enabled ? "enabled" : "disabled")} for the '{account}' account.");
}
2 changes: 1 addition & 1 deletion examples/FeatureFlagDemo/Controllers/HomeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public async Task<IActionResult> About()
if (await _featureManager.IsEnabledAsync(MyFeatureFlags.CustomViewData))
{
ViewData["Message"] = $"This is FANCY CONTENT you can see only if '{MyFeatureFlags.CustomViewData}' is enabled.";
};
}

return View();
}
Expand Down
65 changes: 29 additions & 36 deletions examples/TargetingConsoleApp/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
//
using Microsoft.Extensions.Configuration;
using Microsoft.FeatureManagement;
using Microsoft.FeatureManagement.FeatureFilters;
using TargetingConsoleApp.Identity;
Expand All @@ -10,48 +12,39 @@
.AddJsonFile("appsettings.json")
.Build();

//
// Setup application services + feature management
IServiceCollection services = new ServiceCollection();

services.AddSingleton(configuration)
.AddFeatureManagement();
var featureManager = new FeatureManager(new ConfigurationFeatureDefinitionProvider(configuration))
{
FeatureFilters = new List<IFeatureFilterMetadata> { new ContextualTargetingFilter() }
};

var userRepository = new InMemoryUserRepository();

//
// Get the feature manager from application services
using (ServiceProvider serviceProvider = services.BuildServiceProvider())
// We'll simulate a task to run on behalf of each known user
// To do this we enumerate all the users in our user repository
IEnumerable<string> userIds = InMemoryUserRepository.Users.Select(u => u.Id);

//
// Mimic work items in a task-driven console application
foreach (string userId in userIds)
{
IFeatureManager featureManager = serviceProvider.GetRequiredService<IFeatureManager>();
const string FeatureName = "Beta";

//
// We'll simulate a task to run on behalf of each known user
// To do this we enumerate all the users in our user repository
IEnumerable<string> userIds = InMemoryUserRepository.Users.Select(u => u.Id);
// Get user
User user = await userRepository.GetUser(userId);

//
// Mimic work items in a task-driven console application
foreach (string userId in userIds)
// Check if feature enabled
var targetingContext = new TargetingContext
{
const string FeatureName = "Beta";

//
// Get user
User user = await userRepository.GetUser(userId);

//
// Check if feature enabled
var targetingContext = new TargetingContext
{
UserId = user.Id,
Groups = user.Groups
};

bool enabled = await featureManager.IsEnabledAsync(FeatureName, targetingContext);

//
// Output results
Console.WriteLine($"The {FeatureName} feature is {(enabled ? "enabled" : "disabled")} for the user '{userId}'.");
}
UserId = user.Id,
Groups = user.Groups
};

bool enabled = await featureManager.IsEnabledAsync(FeatureName, targetingContext);

//
// Output results
Console.WriteLine($"The {FeatureName} feature is {(enabled ? "enabled" : "disabled")} for the user '{userId}'.");
}
Loading