Giter Club home page Giter Club logo

flagsmith-dotnet-client's Issues

using .NET client SDK always return "Value cannot be null. Parameter name: value" error

When we use .NET client SDK always return "Value cannot be null. Parameter name: value" error.

When we call .net code like below

        BulletTrainConfiguration configuration = new BulletTrainConfiguration()
        {
            ApiUrl = "https://features.xyz.ca/api/v1/",
            EnvironmentKey = EnvironmentKey
        };

        BulletTrainClient bulletClient = new BulletTrainClient(configuration);
        bool featureEnabled = await BulletTrainClient.instance.HasFeatureFlag("configuration_resource");
        string result = "";
        if (featureEnabled)
        {
            result = " run the code to execute enabled feature";
        }
        else
        {
            result = "run the code if feature switched off";
        } 
        return "value - " + result;

Generate Exception

<Message>An error has occurred.</Message>
<ExceptionMessage>Value cannot be null. Parameter name: value</ExceptionMessage>
<ExceptionType>System.ArgumentNullException</ExceptionType>

After some investigation about the inner HTTP call to the API, we found that the root cause is that :

GET https://features.xyz.ca/api/v1/flags/ HTTP/1.1
X-Environment-Key: xyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxy
Host: features.xyz.ca
Connection: Keep-Alive

This returns :

 HTTP/1.1 403 Forbidden
 Server: awselb/2.0
Date: Thu, 17 Sep 2020 14:26:42 GMT
Content-Type: text/html
Content-Length: 134
Connection: keep-alive

<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
</body>
</html>

After some investigation and compare between .NET SDK and Direct API Access by curl , we found that the direct call to curl is working with same parameters

curl https://features.xyz.ca/api/v1/flags/ -H "X-Environment-Key: xyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxy"

This return all features in JSON.

So, why .NET SDK not working, any Idea?

Fix package validation errors

The following errors are seen when validating a locally built package:

{
  "Packages": {
    "/Users/kgustyr/dev/flagsmith/flagsmith-dotnet-client/Flagsmith.FlagsmithClient/bin/Release/Flagsmith.5.3.0.nupkg": {
      "Errors": [
        {
          "ErrorCode": 101,
          "Message": "XML documentation not found",
          "HelpText": "lib/netstandard2.0/Flagsmith.Engine.dll"
        },
        {
          "ErrorCode": 101,
          "Message": "XML documentation not found",
          "HelpText": "lib/netstandard2.0/Flagsmith.FlagsmithClient.dll"
        },
        {
          "ErrorCode": 111,
          "Message": "Symbol file not found",
          "FileName": "lib/netstandard2.0/Flagsmith.FlagsmithClient.dll"
        },
        {
          "ErrorCode": 111,
          "Message": "Symbol file not found",
          "FileName": "lib/netstandard2.0/Flagsmith.Engine.dll"
        },
        {
          "ErrorCode": 74,
          "Message": "Repository commit is not set"
        },
        {
          "ErrorCode": 72,
          "Message": "Repository type is not set"
        },
        {
          "ErrorCode": 61,
          "Message": "Readme is not set"
        },
        {
          "ErrorCode": 12,
          "Message": "\u003Cauthors\u003E element is not set explicitly (same as \u003Cid\u003E)"
        }
      ]
    }
  }
}

These need to be resolved and removed from the --excluded-rule-ids validator argument in the release workflow.

Question: DI registration example

Hi guys!
I see in the example you register Flagsmith client as singleton, but in fact this is a typed httpclient.
Is it better to use this approach mb?

services.Configure<FlagsmithConfiguration>(builder.Configuration.GetSection(nameof(FlagsmithConfiguration)));
services.AddHttpClient<IFlagsmithClient, FlagsmithClient>(nameof(FlagsmithClient));

Because static/singleton HttpClient doesn't respect DNS changes and is considered bad practice. See details here

Not getting flags after hitting request second time from method GetIdentityFlags

I have incorporated SDK 5.1.0 and implemented the below code in ASP.NET MVC application (not core) which is running on .NET 4.7.2.

using Flagsmith;
using System;
using System.Configuration;
using System.Threading.Tasks;

namespace FeatureFlagHelper
{
    public class FlagsmithClientHelper
    {
        private readonly IFlagsmithClient _flagsmithClient;

        public FlagsmithClientHelper()
        {
            FlagsmithConfiguration configuration = new FlagsmithConfiguration()
            {
                EnvironmentKey = ConfigurationManager.AppSettings["FlagsmithEnvironmentKey"],
                EnableClientSideEvaluation = Convert.ToBoolean(ConfigurationManager.AppSettings["EnableClientSideEvaluation"]),
                EnvironmentRefreshIntervalSeconds = Convert.ToInt32(ConfigurationManager.AppSettings["EnvironmentRefreshIntervalSeconds"]),
                EnableAnalytics = Convert.ToBoolean(ConfigurationManager.AppSettings["EnableAnalytics"]),
                RequestTimeout = Convert.ToDouble(ConfigurationManager.AppSettings["RequestTimeout"]),
                Retries = Convert.ToInt32(ConfigurationManager.AppSettings["Retries"])

            };

            _flagsmithClient = new FlagsmithClient(configuration);
        }

        public async Task<bool> IsFlagEnabled(string flagName, string identity)
        {
            var flags = await this._flagsmithClient.GetIdentityFlags(identity, null);
            var flagStatus = await flags.IsFeatureEnabled(flagName.ToLower());

            return flagStatus;
        }
    }
}

I am calling this class post initializing and am trying to get the flagStatus whether it is turned on or off. Like this

 public static bool IsSomeFlagEnabled(string email)
        {
            var flagsmithClientHelper = new FlagsmithClientHelper();
            return flagsmithClientHelper.IsFlagEnabled("issomeflagenabled", "[email protected]").Result;
        } 

Now this code works perfectly fine when it fetches the flag status the very first time but once the second calls comes to get the flag status this piece of code goes in wait and the debugger never returns to the next statement:

var flags = await this._flagsmithClient.GetIdentityFlags(identity, null);

After above code the debugger doesn't return to the code. it's like the thread has gone in infinite wait.
I have to reset IIS and start the application again to get rid of this infinite wait issue.
Please help me with the fix.

image

Flagsmith Hangs Indefinitely

Hello,

Our team is recently exploring the option of using Flagsmith on our application running .net framework 4.7.3
During our implementation, we discovered two cases where it leads to indefinite hanging when trying to get flags from flagsmith.

Case 1 : Initializing Client with CacheConfig

In our testing, we have found that setting CacheConfig results in indefinite hanging issue when FlagsmithClient.GetEnvironmentFlags is called

var cacheConfig = new CacheConfig(true)
            {
                DurationInMinutes = 1
            };
var flagsmithConfiguration = new FlagsmithConfiguration
            {
                EnvironmentKey = flagsmithEnvKey,
                CacheConfig = cacheConfig
            };
FlagsmithClient = new FlagsmithClient(flagsmithConfiguration);

Case 2 : Getting Environment Flags Synchronously

Based on the docs, we were not able to get the environment flags synchronously and observed that the call also hangs indefinitely. Please note that at this point, we have disabled CacheConfig setting to avoid issue from case 1.

The issue only happens when we tried to hit it synchronously. If we were to await the call, the flags do come back swiftly.

I.E.
flagsmithClient.GetEnvironmentFlags().Result; -> hangs
await flagsmithClient.GetEnvironmentFlags(); -> works just fine

Please keep in mind that we are using .net framework 4.7.3 and do not have the capability to upgrade to later versions.

Any help is greatly appreciated. Please let me know if more information is needed.
Thank you!

Indefinite hang in MVC view, only where EnableAnalytics is set to true

Similar to issue #105, we're seeing that requests hang indefinitely.

Specifically, this is happening in MVC Razor Views (4.8) where EnableAnalytics is set to true.

When setting EnableAnalytics to false, we do not see the problem. Also, we did not seem to notice any issue with EnableAnalytics, when flags are accessed from MVC Controller methods.

Exception: System.ThrowHelper.ThrowInvalidOperationException_ConcurrentOperationsNotSupported

Hi,
We were getting this error in production environment on one of our pods:

Screenshot 2024-01-24 at 14 26 26

It started yesterday evening, and restarting of the pod stopped it. We followed your example how to register service, also didn't have any related changes recently. Stack pointing to this one:

public async Task TrackFeature(string featureName)
    {
      int num;
      this.AnalyticsData[featureName] = this.AnalyticsData.TryGetValue(featureName, out num) ? num + 1 : 1;
      if ((DateTime.Now - this._LastFlushed).Seconds <= this._FlushIntervalSeconds)
        return;
      await this.Flush();
    } 

Do you have any idea why this happened, could it be related to lack of thread safety?

We are using version 5.0.1

Caching does not implement a max size

Currently the caching implementation does not implement a max size. We should add a configurable limit to the size of the cache to ensure that there are no memory concerns when using the cache implementation in the client.

FlagsmithClient's interface was completely changed

Hi,

We were using Flagsmith 3.1.0 nuget package and thought to upgrade and it seems that all the interface has changed...
Was the 3.1.0 a beta release? What are the plans with the future releases? Are there any breaking changes expected there?
We see that there is no SetTraits method in the new interface. So how do we add users and traits dynamically in the new version?

Thanks,
Sveta

Can't install SDK on new projects

I was trying to install the SDK version 4.0.0. on a project that throws the error.

Severity	Code	Description	Project	File	Line	Suppression State
Error	NU1101	Unable to find package Flagsmith.Engine. No packages exist with this id in source(s): Microsoft Visual Studio Offline Packages, nuget.org	Todo	D:\projects\xamarin-forms-samples\Todo\Todo\Todo\Todo.csproj	1	

Later, I created a new xamarin project(to check if it works on .Net 6) it still showed the same error while installing the nuget package

small question why doesn't /flags API return tags?

Identity overrides in local evaluation mode

  1. Extend the Environment model with the identity_overrides: List[IdentityModel] field.
  2. On environment update in local evaluation mode, store overrides so they're efficiently accessed by identifier.
  3. For GetIdentityFlagsFromDocument interface, use the storage above to retrieve the identity overrides. Fall back to a new IdentityModel instance if not found. If found, update traits with user-provided traits.

Refer to the following existing implementations:

Flagsmith/flagsmith-python-client#72
Flagsmith/flagsmith-java-client#142
Flagsmith/flagsmith-nodejs-client#143

When identity is specified a redundant slash character is added in the end

Hi,

I've noticed that if I use identity, then a user is added with incorrect id, such as user_id/. It's because of AppendPath in the class UrlExtension.
There are two consequences from this:

  1. the user has additional slash which wasn't specified in the client application
  2. BulletTrain Web doesn't correctly show user with additional slash.

At the same time this is not crucial issue. It is still possible to use Web and Api with this identity.

Regards,

Don't log errors using Console.WriteLine

Example:

Console.WriteLine("\nJSON Exception Caught!");

There is no guarantee that the process has a console, and if it doesn't then an attempt to write to the non-existent console can bring down the entire application. Ideally you'd want to use a proper logging framework, but since the usage here is relatively limited you could implement a simple check before writing to the console: if (Console.WindowHeight > 0) { Console.WriteLine("Error"); }

Implement SDK-side Caching

Hi There,

It looks like the .Net client does a request to the endpoint every single time, any plans to cache the flags on the backend, say for 30 seconds?

HttpClient is intended to be instantiated once and re-used throughout the life of an application

https://github.com/SolidStateGroup/bullet-train-dotnet-client/blob/12413ec6b940479feec5df1180377aa226003d04/BulletTrainClient.cs#L158

HttpClient is intended to be instantiated once and re-used throughout the life of an application. Instantiating an HttpClient class for every request will exhaust the number of sockets available under heavy loads. This will result in SocketException errors. See
https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient?view=netframework-4.7.2

Be aware of the DNS issue described here
http://byterot.blogspot.com/2016/07/singleton-httpclient-dns.html

When called consecutively, HasFeatureFlag method gets an error on the second run

I've been trying 2.0.0 BulletTrain Client SDK on a .NetCore 3.1 WebApi project and on a Console application. For Api calls, my initial plan was to run an on-prem version on Docker. But also I tried "https://app.bullet-train.io/" with a free account.

  • Console Application works properly. But WebApi project fails when a second call is made to the BulletTrain Api.

  • So here's my sample code for Console App,

            BulletTrainConfiguration configuration = new BulletTrainConfiguration()
            {
                ApiUrl = "http://localhost:8000/api/v1/",
                EnvironmentKey = "my-local-env-key"
            };

            BulletTrainClient bulletClient = new BulletTrainClient(configuration);
            bool featureEnabled = await bulletClient.HasFeatureFlag("is_it_weekend");
                if (featureEnabled) {
                    // Run the code to execute enabled feature
                    Console.WriteLine("Hello World!");
                } else {
                    // Run the code if feature switched off
                    Console.WriteLine("GoodBye World!");
                }
  • Here is the sample code from the WebApi project, they're almost identical (I used BulletTrain docs for implementation)
            BulletTrainConfiguration configuration = new BulletTrainConfiguration()
            {
                ApiUrl = "http://localhost:8000/api/v1/",
                EnvironmentKey = "my-local-env-key"
            };

            BulletTrainClient bulletClient = new BulletTrainClient(configuration);
            bool featureEnabled = await bulletClient.HasFeatureFlag("is_it_weekend");
            if (featureEnabled) {
                // Run the code to execute enabled feature
                return Ok(myWeekendItem);
            } else {
                // Run the code if feature switched off
                return NotFound();
            }
  • When I run it for the first time, it works properly. Without even changing anything, when I run on the web api the second time, it throws the below exception:

Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware: Error: An unhandled exception has occurred while executing the request.

System.NullReferenceException: Object reference not set to an instance of an object.
at BulletTrain.BulletTrainClient.GetFeatureFlags(String identity)
at BulletTrain.BulletTrainClient.HasFeatureFlag(String featureId, String identity)
at Glossary.Controllers.GlossaryController.Get(String term) in /Users/sevikarakose/Projects/Glossary/Controllers/GlossaryController.cs:line 52
at lambda_method(Closure , Object )
at Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult()
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Providing an OfflineHandler causes the SDK to bypass live flag lookups (even if OfflineMode is false)

Bug Report

.NET SDK Version: 5.3.0

Description of problem

We're trying to make use of the offline handler feature to provide default flags if the SDK cannot contact our Flagsmith server for some reason. I.e., we're trying to use it for scenario 2 listed in this section of your documentation: https://docs.flagsmith.com/clients/server-side#using-an-offline-handler.

We have OfflineMode disabled, and have an instance of your LocalFileHandler class set as the offline handler. This is how we're instantiating the FlagsmithClient class when we register it with DI:
image

Expected Behavior

The SDK should still attempt live API calls to our Flagsmith server to obtain flag values, only using the offline handler as a fallback if the live API calls fail.

Actual Behavior

The SDK never attempts any live API calls, it just uses the offline file directly.

Analysis

The bug is easily reproducible because we can change the value of a flag on the Flagsmith server, but if we debug our code, the results of the FlagsmithClient.GetEnvironmentFlags() call shows us that the flag always has its offline file value.

Looking at the source code for FlagsmithClient, the cause becomes clear:

  • GetEnvironmentFlags() calls GetFeatureFlagsFromCorrectSource()
  • GetFeatureFlagsFromCorrectSource() is implemented to choose between a locally-loaded Environment model or a live API call based on whether the Environment variable is non-null:
    private async Task<IFlags> GetFeatureFlagsFromCorrectSource()
    {
    return Environment != null ? GetFeatureFlagsFromDocument() : await GetFeatureFlagsFromApi();
    }
  • The Environment variable is always non-null because in the constructor, it is always set from the offline handler if an offline handler is present:
    if (_offlineHandler != null)
    {
    Environment = _offlineHandler.GetEnvironment();
    }

Requested Changes

Please change the logic of the FlagsmithClient such that the Environment model is not automatically registered from the offline handler during construction if offline mode is false. I am not sure what-all considerations will need to be made in order to make this change, but that's the basic idea.

As it stands, this bug completely invalidates the scenario of using an offline handler for default flag handling, so we would appreciate it if it could be fixed with some priority.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.