W jednym z ostatnich artykułów poruszyłem temat mechanizmu flag funkcjonalnści i ich integracji z serwerem Gitlab-a (Gitlab – Feature Toggles) . Tym razem planuje rozwinąć temat implementacji Permissioning toggles za pomocą klienta serwer-a Unleash. Jeżeli nie czytałeś wcześniejszego artykułu to zachęcam Cię do zapoznania się z nim.

Czym są Permissioning Toggles?

Zacznijmy od krótkiego przypomnienia czym są Permissioning Toogles. W dużym skrócie są to flagi, w których dostęp do funkcjonalności ma tylko zdefiniowane grono użytkowników. Dla celów artykułu będziemy bazować na wartościach Id użytkowników.

Utworzenie Toggle w Gitlab

Wykorzystanie flagi funkcjonalności wymaga przejścia do swojego projektu w Gitlabie. W menu bocznym, w sekcji Operations, znajdziemy zakładkę Feature Flags. Sam proces tworzenia podstawowych wersji flag funkcjonalności opisałem w poprzednim artykule, skupie się więc tylko na różnicach. W tym przypadku będzie to modyfikacja strategii na dole formularza. W momencie, kiedy tworzymy flagę, naszą domyślną strategią jest All Users – flaga będzie się zachowywać tak samo dla każdego użytkownika. Wykorzystanie Permissioning toggles wymaga zmiany strategii na User IDs w liście rozwijanej. Po prawej stronie od listy pojawi się pole tekstowe do wpisania id-ków użytkowników, dla których flaga ma być włączona. W moim przypadku będą to użytkownicy 12 i 123.

Cała konfiguracja jest przedstawiona na poniższym obrazku:

Integracja z klientem Unleash

Wypróbujmy działanie integracji ręcznie ustawiając id użytkownika w kontekście Unleash. Wróćmy do przykładu z poprzedniego artykułu. W kontrolerze mieliśmy  implementację flagi funkcjonalności. Dodaj tylko pobieranie parametru userId jako parametru z adresu url.

[HttpGet("/Feature")]
public IActionResult Feature(string userId)
{
    var context = new UnleashContext
    {
         UserId = userId
    };
    
    if (_unleash.IsEnabled("my_awesome_feature", context))
        return Ok("Feature on!");
    return Ok("Feature off!");
}

Jak widzisz samo utworzenie kontekstu jest bardzo proste, szczególnie, że mamy dostępne pole o nazwie UserId. Zwróć uwagę, że metoda IsEnabled z klienta Unleash może przyjąć obiekt UnleashContext jako swój drugi parametr.
Oczywiście ten sposób implementacji nie nadaje się do kodu produkcyjnego, ale pozwala nam na szybkie zweryfikowanie, czy wszystko działa poprawnie. Wystarczą dwa wywołania adresu z poziomu przeglądarki i już wiemy, że wszystko wygląda dobrze.

Integracja z HttpContext

Jako programista nie wyobrażam sobie konieczności pamiętania, by za każdym razem tworzyć obiekt klasy UnleashContext tak, aby korzystać z dobrodziejstw flag funkcjonalności. Na szczęście, w prosty sposób, możemy zintegrować klient-a Unleash z klasą HttpContext, która przechowuje informacje o użytkowniku.

Pierwszy krokiem będzie stworzenie klasy, która implementuje interfejs IUnleashContextProvider.

public class CustomUnleashContextProvider : IUnleashContextProvider
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public UnleashContextProvider(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }
    public UnleashContext Context => new UnleashContext
    {
        UserId = _httpContextAccessor.HttpContext?.User.FindFirstValue(ClaimTypes.NameIdentifier)
    };
}

Najważniejszym elementem jest oczywiście property Context, w którym tworzymy UnleashContext na bazie obecnego kontekstu zapytania HTTP. Oczywiście możemy przekazać dużo więcej informacji do kontekstu, takich jak nazwa środowiska, identyfikator sesji etc. Na ten moment wystarczy tylko id użytkownika.
Kolejnym krokiem jest zmiana w pliku Startup.cs gdzie wcześniej była tworzona instancja klient-a Unleash.

var accessor = new HttpContextAccessor();

var settings = new UnleashSettings
{
    AppName = "dotnet-test",
    InstanceTag = "xyz",
    UnleashApi = new Uri("https://gitlab.com/api/v4/feature_flags/unleash/xyz"),
    UnleashContextProvider = new CustomUnleashContextProvider(accessor)
};

var unleash = new DefaultUnleash(settings);

services.AddSingleton(unleash);

Jako, że do obiektu UnleashSettings musimy przekazać HttpContextAccessor zdecydowałem się utworzyć go ręcznie. Oczywiście istnieje możliwość wcześniejszego zarejestrowania go w kontenerze DI, jednak wymaga to zbudowania ServiceProvider-a, co może skutkować niepożądanymi zachowaniami.

Dzięki temu że nasz unleashContext jest przekazywany automatycznie, to możemy się pozbyć kodu odpowiedzialnego za jego tworzenie z kontrolera.

Podsumowanie

Dzisiaj artykuł dość krótki, jednak mam nadzieje, że dobrze wypełniony “mięskiem”. Liczę, że się podobał 😀
Do Następnego!

PS. Spodobał Ci się ten artykuł?

Referencje