From 224e19528836cfb1b3b76c0d113083a728856ad7 Mon Sep 17 00:00:00 2001 From: Md Junaed Hossain <169046794+junaed-optimizely@users.noreply.github.com> Date: Thu, 13 Nov 2025 22:46:46 +0600 Subject: [PATCH 1/5] [FSSDK-11956] CMAB Release C# --- CHANGELOG.md | 44 +++++++++++++++++++ .../Properties/AssemblyInfo.cs | 6 +-- .../Properties/AssemblyInfo.cs | 6 +-- .../Properties/AssemblyInfo.cs | 6 +-- .../Properties/AssemblyInfo.cs | 6 +-- .../Properties/AssemblyInfo.cs | 6 +-- .../Properties/AssemblyInfo.cs | 6 +-- OptimizelySDK/Properties/AssemblyInfo.cs | 6 +-- README.md | 2 +- 9 files changed, 66 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dca45cda..0686fcdf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,49 @@ # Optimizely C# SDK Changelog +## 4.2.0 +Nov 13, 2025 + +### New Features + +- **Added support for Contextual Multi-Armed Bandit (CMAB)**: Added support for CMAB experiments(Contextual Bandits rules) with new configuration options and cache control. To get decision from CMAB rules, `decide` and related methods must be used. + +#### CMAB Configuration Options + +The following new configuration options have been added for CMAB: + +```csharp +using OptimizelySDK; + +// Configure CMAB settings before creating the Optimizely instance +var cmabConfig = new CmabConfig() + .SetCacheSize(1000) // Optional: Set CMAB cache size (default: 1000) + .SetCacheTtl(TimeSpan.FromMinutes(30)); // Optional: Set CMAB cache TTL (default: 30 minutes) + // .SetCache(customCache) // Optional: Custom cache implementation + +OptimizelyFactory.SetCmabConfig(cmabConfig); + +var optimizely = OptimizelyFactory.NewDefaultInstance("SDK_KEY_HERE"); +``` + +#### CMAB-Related OptimizelyDecideOptions + +New decide options are available to control CMAB caching behavior: + +- `OptimizelyDecideOption.IGNORE_CMAB_CACHE`: Bypass CMAB cache for fresh decisions +- `OptimizelyDecideOption.RESET_CMAB_CACHE`: Clear and reset CMAB cache before making decisions +- `OptimizelyDecideOption.INVALIDATE_USER_CMAB_CACHE`: Invalidate CMAB cache for the particular user and experiment + +```csharp +using OptimizelySDK.OptimizelyDecisions; + +// Example usage with CMAB decide options +var user = optimizely.CreateUserContext("user123"); +var decision = user.Decide("feature-flag-key", new[] +{ + OptimizelyDecideOption.IGNORE_CMAB_CACHE +}); +``` + ## 4.1.0 November 7th, 2024 diff --git a/OptimizelySDK.DemoApp/Properties/AssemblyInfo.cs b/OptimizelySDK.DemoApp/Properties/AssemblyInfo.cs index 147aa1a8..40772131 100644 --- a/OptimizelySDK.DemoApp/Properties/AssemblyInfo.cs +++ b/OptimizelySDK.DemoApp/Properties/AssemblyInfo.cs @@ -37,6 +37,6 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("4.1.0.0")] -[assembly: AssemblyFileVersion("4.1.0.0")] -[assembly: AssemblyInformationalVersion("4.1.0")] // Used by NuGet. +[assembly: AssemblyVersion("4.2.0.0")] +[assembly: AssemblyFileVersion("4.2.0.0")] +[assembly: AssemblyInformationalVersion("4.2.0")] // Used by NuGet. diff --git a/OptimizelySDK.Net35/Properties/AssemblyInfo.cs b/OptimizelySDK.Net35/Properties/AssemblyInfo.cs index dd5b9ab2..77c07883 100644 --- a/OptimizelySDK.Net35/Properties/AssemblyInfo.cs +++ b/OptimizelySDK.Net35/Properties/AssemblyInfo.cs @@ -37,6 +37,6 @@ // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("4.1.0.0")] -[assembly: AssemblyFileVersion("4.1.0.0")] -[assembly: AssemblyInformationalVersion("4.1.0")] // Used by NuGet. +[assembly: AssemblyVersion("4.2.0.0")] +[assembly: AssemblyFileVersion("4.2.0.0")] +[assembly: AssemblyInformationalVersion("4.2.0")] // Used by NuGet. diff --git a/OptimizelySDK.Net40/Properties/AssemblyInfo.cs b/OptimizelySDK.Net40/Properties/AssemblyInfo.cs index 48b0cb1d..368d2d5f 100644 --- a/OptimizelySDK.Net40/Properties/AssemblyInfo.cs +++ b/OptimizelySDK.Net40/Properties/AssemblyInfo.cs @@ -37,6 +37,6 @@ // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("4.1.0.0")] -[assembly: AssemblyFileVersion("4.1.0.0")] -[assembly: AssemblyInformationalVersion("4.1.0")] // Used by NuGet. +[assembly: AssemblyVersion("4.2.0.0")] +[assembly: AssemblyFileVersion("4.2.0.0")] +[assembly: AssemblyInformationalVersion("4.2.0")] // Used by NuGet. diff --git a/OptimizelySDK.NetStandard16/Properties/AssemblyInfo.cs b/OptimizelySDK.NetStandard16/Properties/AssemblyInfo.cs index f82a11ad..018b6364 100644 --- a/OptimizelySDK.NetStandard16/Properties/AssemblyInfo.cs +++ b/OptimizelySDK.NetStandard16/Properties/AssemblyInfo.cs @@ -37,6 +37,6 @@ // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("4.1.0")] -[assembly: AssemblyFileVersion("4.1.0.0")] -[assembly: AssemblyInformationalVersion("4.1.0")] // Used by NuGet. +[assembly: AssemblyVersion("4.2.0")] +[assembly: AssemblyFileVersion("4.2.0.0")] +[assembly: AssemblyInformationalVersion("4.2.0")] // Used by NuGet. diff --git a/OptimizelySDK.NetStandard20/Properties/AssemblyInfo.cs b/OptimizelySDK.NetStandard20/Properties/AssemblyInfo.cs index 72640cfa..9a9f2211 100644 --- a/OptimizelySDK.NetStandard20/Properties/AssemblyInfo.cs +++ b/OptimizelySDK.NetStandard20/Properties/AssemblyInfo.cs @@ -37,6 +37,6 @@ // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("4.1.0.0")] -[assembly: AssemblyFileVersion("4.1.0.0")] -[assembly: AssemblyInformationalVersion("4.1.0")] // Used by NuGet. +[assembly: AssemblyVersion("4.2.0.0")] +[assembly: AssemblyFileVersion("4.2.0.0")] +[assembly: AssemblyInformationalVersion("4.2.0")] // Used by NuGet. diff --git a/OptimizelySDK.Tests/Properties/AssemblyInfo.cs b/OptimizelySDK.Tests/Properties/AssemblyInfo.cs index f122893f..af81c50f 100644 --- a/OptimizelySDK.Tests/Properties/AssemblyInfo.cs +++ b/OptimizelySDK.Tests/Properties/AssemblyInfo.cs @@ -30,6 +30,6 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("4.1.0.0")] -[assembly: AssemblyFileVersion("4.1.0.0")] -[assembly: AssemblyInformationalVersion("4.1.0")] // Used by NuGet. +[assembly: AssemblyVersion("4.2.0.0")] +[assembly: AssemblyFileVersion("4.2.0.0")] +[assembly: AssemblyInformationalVersion("4.2.0")] // Used by NuGet. diff --git a/OptimizelySDK/Properties/AssemblyInfo.cs b/OptimizelySDK/Properties/AssemblyInfo.cs index 96d04867..c06a0d5d 100644 --- a/OptimizelySDK/Properties/AssemblyInfo.cs +++ b/OptimizelySDK/Properties/AssemblyInfo.cs @@ -41,6 +41,6 @@ // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("4.1.0.0")] -[assembly: AssemblyFileVersion("4.1.0.0")] -[assembly: AssemblyInformationalVersion("4.1.0")] // Used by NuGet. +[assembly: AssemblyVersion("4.2.0.0")] +[assembly: AssemblyFileVersion("4.2.0.0")] +[assembly: AssemblyInformationalVersion("4.2.0")] // Used by NuGet. diff --git a/README.md b/README.md index 9de4ddc7..9d21c7e4 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ User can provide variables using following procedure: ```
+ type="OptimizelySDK.OptimizelySDKConfigSection, OptimizelySDK, Version=4.2.0.0, Culture=neutral, PublicKeyToken=null" /> ``` 2. Now add **optlySDKConfigSection** below ****. In this section you can add and set following **HttpProjectConfigManager** and **BatchEventProcessor** variables: From f5f1e25c6c1754ed3374841d33a026fc35e1b05f Mon Sep 17 00:00:00 2001 From: Md Junaed Hossain <169046794+junaed-optimizely@users.noreply.github.com> Date: Fri, 14 Nov 2025 00:06:22 +0600 Subject: [PATCH 2/5] [FSSDK-11956] pipeline --- .github/workflows/csharp_release.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/csharp_release.yml b/.github/workflows/csharp_release.yml index f4c1736c..24e8dae2 100644 --- a/.github/workflows/csharp_release.yml +++ b/.github/workflows/csharp_release.yml @@ -23,9 +23,11 @@ jobs: exit 1 fi echo "Extracted semantic version: ${SEMANTIC_VERSION}" + echo "Resolved git ref: ${TAG}" + echo "tag=${TAG}" >> $GITHUB_OUTPUT echo "semantic_version=${SEMANTIC_VERSION}" >> $GITHUB_OUTPUT outputs: - tag: $TAG + tag: ${{ steps.set_version.outputs.tag }} semanticVersion: ${{ steps.set_version.outputs.semantic_version }} buildFrameworkVersions: From 9a8a65b8d46c109b49dfb1b61574b0f5873696e0 Mon Sep 17 00:00:00 2001 From: Md Junaed Hossain <169046794+junaed-optimizely@users.noreply.github.com> Date: Fri, 14 Nov 2025 14:51:39 +0600 Subject: [PATCH 3/5] [FSSDK-11956] manual workflow update --- .github/workflows/csharp_release.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/csharp_release.yml b/.github/workflows/csharp_release.yml index 24e8dae2..1836c73d 100644 --- a/.github/workflows/csharp_release.yml +++ b/.github/workflows/csharp_release.yml @@ -3,18 +3,28 @@ on: release: types: [ published ] # Trigger on published pre-releases and releases - workflow_dispatch: + workflow_dispatch: + inputs: + tag: + description: 'Tag to build (e.g., v4.2.0)' + required: true + type: string jobs: variables: name: Set Variables runs-on: ubuntu-latest env: - TAG: ${{ github.event.release.tag_name }} + TAG: ${{ github.event.release.tag_name || inputs.tag }} steps: - name: Extract semantic version from tag id: set_version run: | + if [ -z "${TAG}" ]; then + echo "Error: No release tag available. Please provide a tag when manually triggering the workflow." + exit 1 + fi + echo "Processing tag: ${TAG}" # Remove the "v" prefix if it exists and extract the semantic version number SEMANTIC_VERSION=$(echo "${TAG}" | grep -Po "(?<=^|[^0-9])([0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?(-[a-zA-Z]+[0-9]*)?)") SEMANTIC_VERSION=${SEMANTIC_VERSION#"v"} From d96ff06b67e77cbfbfcb2724d540c15885947b20 Mon Sep 17 00:00:00 2001 From: Md Junaed Hossain <169046794+junaed-optimizely@users.noreply.github.com> Date: Fri, 14 Nov 2025 15:30:25 +0600 Subject: [PATCH 4/5] [FSSDK-11956] making upload sequential --- .github/workflows/csharp_release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/csharp_release.yml b/.github/workflows/csharp_release.yml index 1836c73d..fcdc06f8 100644 --- a/.github/workflows/csharp_release.yml +++ b/.github/workflows/csharp_release.yml @@ -102,7 +102,7 @@ jobs: buildStandard16: name: Build Standard 1.6 version - needs: [ variables ] + needs: [ variables, buildFrameworkVersions ] runs-on: windows-2022 steps: - name: Checkout code @@ -124,7 +124,7 @@ jobs: buildStandard20: name: Build Standard 2.0 version - needs: [ variables ] + needs: [ variables, buildStandard16 ] runs-on: windows-2022 steps: - name: Checkout code From 3625ac73d1a384972e61af701e6390f8d6ed763f Mon Sep 17 00:00:00 2001 From: Md Junaed Hossain <169046794+junaed-optimizely@users.noreply.github.com> Date: Fri, 14 Nov 2025 15:39:38 +0600 Subject: [PATCH 5/5] [FSSDK-11956] making upload parallel + artifact name change --- .github/workflows/csharp_release.yml | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/.github/workflows/csharp_release.yml b/.github/workflows/csharp_release.yml index fcdc06f8..adfce8bb 100644 --- a/.github/workflows/csharp_release.yml +++ b/.github/workflows/csharp_release.yml @@ -96,13 +96,13 @@ jobs: - name: Upload Framework artifacts uses: actions/upload-artifact@v4 with: - name: unsigned-dlls + name: unsigned-dlls-framework if-no-files-found: error path: ./**/bin/Release/**/Optimizely*.dll buildStandard16: name: Build Standard 1.6 version - needs: [ variables, buildFrameworkVersions ] + needs: [ variables ] runs-on: windows-2022 steps: - name: Checkout code @@ -118,13 +118,13 @@ jobs: - name: Upload Standard 1.6 artifact uses: actions/upload-artifact@v4 with: - name: unsigned-dlls + name: unsigned-dlls-netstandard16 if-no-files-found: error path: ./**/bin/Release/**/Optimizely*.dll buildStandard20: name: Build Standard 2.0 version - needs: [ variables, buildStandard16 ] + needs: [ variables ] runs-on: windows-2022 steps: - name: Checkout code @@ -137,10 +137,10 @@ jobs: run: dotnet restore OptimizelySDK.NetStandard20/OptimizelySDK.NetStandard20.csproj - name: Build and strongly name Standard 2.0 project run: dotnet build OptimizelySDK.NetStandard20/OptimizelySDK.NetStandard20.csproj /p:SignAssembly=true /p:AssemblyOriginatorKeyFile=$(pwd)/keypair.snk -c Release - - name: Build and strongly name assemblies + - name: Upload Standard 2.0 artifacts uses: actions/upload-artifact@v4 with: - name: unsigned-dlls + name: unsigned-dlls-netstandard20 if-no-files-found: error path: ./**/bin/Release/**/Optimizely*.dll @@ -158,10 +158,20 @@ jobs: # TODO: Remove this when we're ready to automate - name: Temporarily halt progress run: exit 1 - - name: Download the unsigned files + - name: Download Framework DLLs + uses: actions/download-artifact@v4 + with: + name: unsigned-dlls-framework + path: ./unsigned-dlls + - name: Download NetStandard 1.6 DLLs + uses: actions/download-artifact@v4 + with: + name: unsigned-dlls-netstandard16 + path: ./unsigned-dlls + - name: Download NetStandard 2.0 DLLs uses: actions/download-artifact@v4 with: - name: unsigned-dlls + name: unsigned-dlls-netstandard20 path: ./unsigned-dlls - name: Setup SSH uses: shimataro/ssh-key-action@v2