Data storage danych użytkownika

0

Hej, szukam optymalnego rozwiązania dla przechowywania niewrażliwych user related danych dla użytkownika aplikacji ASP.NET Core, typu dane wyszukiwania oraz liczniki kliknięć.

Po zapoznaniu się z dokumentacją najciekawsze się wydają:

  • Session state,
  • TempData,
  • może jakieś inne?

Do tych danych będę potrzebował dostępu w filtrach akcji, z tym nie przewiduję problemów dla obu rozwiązań. Nie wiem jeszcze (najpóźniej jutro poszukam) które sposoby pozwalają na wywołanie metody na koniec sesji, kiedy użytkownik wyłączy witrynę, w celu np zapisu do DB. Choć założę się, że ASP.NET Core posiada jakiś mechanizm który odpala event na koniec sesji, przynajmniej ja bym tak to wymyślił ;p (też się zabiorę za szukanie niebawem).

Ważę za i przeciw obu rozwiązań. Wydaje mi się, że TempData wygrywa, bo jest przechowywane w backend, a Session state to ciasteczka. Pewnie też przez to wypada lepiej wydajnościowo. Choć z drugiej strony Session state nie obciąża ramu serwera (hostuję na bieda-serwerze), tylko przeglądarkę. Co Wy o tym sądzicie?

2
bakunet napisał(a):

Do tych danych będę potrzebował dostępu w filtrach akcji, z tym nie przewiduję problemów dla obu rozwiązań. Nie wiem jeszcze (najpóźniej jutro poszukam) które sposoby pozwalają na wywołanie metody na koniec sesji, kiedy użytkownik wyłączy witrynę, w celu np zapisu do DB. Choć założę się, że ASP.NET Core posiada jakiś mechanizm który odpala event na koniec sesji, przynajmniej ja bym tak to wymyślił ;p (też się zabiorę za szukanie niebawem).

Ale co to znaczy "na koniec sesji"? Użytkownik kliknie przycisk "wyloguj"? Wygaśnie ciasteczko sesyjne? Zamknie przeglądarkę?

Wydaje mi się, że TempData wygrywa, bo jest przechowywane w backend, a Session state to ciasteczka. Pewnie też przez to wypada lepiej wydajnościowo. Choć z drugiej strony Session state nie obciąża ramu serwera (hostuję na bieda-serwerze), tylko przeglądarkę. Co Wy o tym sądzicie?

Sądzę, że nie przeczytałeś dokładnie. TempData służy do przekazania między dwoma requestami, czyli coś wstawiasz w poście i robisz redirecta do get, a tam możesz z TempData odczytać.
A sesja jest trzymana na serwerze, nie w przeglądarce. Ciasteczko służy do identyfikowania requestu z sesją.

0
somekind napisał(a):

Ale co to znaczy "na koniec sesji"? Użytkownik kliknie przycisk "wyloguj"? Wygaśnie ciasteczko sesyjne? Zamknie przeglądarkę?

To jest bardzo dobre pytanie. Chodzi mi głównie o sytuację w której użytkownik zamknie przeglądarkę. Nie można liczyć na to, że zawsze się wyloguje. Rozejrzałem się za ewentualnym rozwiązaniem i wpadłem na tą dyskusję. Też po stronie serwera nie będę w stanie sprawdzić czy sesja wygasła, jeśli użytkownik zamknie przeglądarkę przed jej wygaśnięciem, to w nawiązaniu do tej odpowiedzi na SO.

Wydaje mi się, że pozostaje mi wykorzystanie mechanizmu który by działał w kontrolerze w oparciu o żądania HTTP.

somekind napisał(a):

Sądzę, że nie przeczytałeś dokładnie. TempData służy do przekazania między dwoma requestami, czyli coś wstawiasz w poście i robisz redirecta do get, a tam możesz z TempData odczytać.
A sesja jest trzymana na serwerze, nie w przeglądarce. Ciasteczko służy do identyfikowania requestu z sesją.

Ok, w takim razie źle zrozumiałem mechanizm dla Session state. A co do TempData, to jeśli będzie odczytany przy wybranych żądaniach HTTP, np. niektórych [HttpGet] kontrolera, to w zupełności mi wystarczy.

1
bakunet napisał(a):

A co do TempData, to jeśli będzie odczytany przy wybranych żądaniach HTTP, np. niektórych [HttpGet] kontrolera, to w zupełności mi wystarczy.

Ale to nie jest czytane przy wybranych, tylko przy jednym następnym.

0

co właściwie chcesz zrobić?

0
WeiXiao napisał(a):

co właściwie chcesz zrobić?

bakunet napisał(a):

Hej, szukam optymalnego rozwiązania dla przechowywania niewrażliwych user related danych dla użytkownika aplikacji ASP.NET Core, typu dane wyszukiwania oraz liczniki kliknięć.

(...)
które sposoby pozwalają na wywołanie metody na koniec sesji, kiedy użytkownik wyłączy witrynę, w celu np zapisu do DB.

Więc, tak ogólnie, między żądaniami HTTP chcę przekazywać liczniki kliknięć i ew. customowy obiekt, i też na koniec sesji zapisać dane do DB. Choć to drugie najpewniej będę robił też przy okazji wysyłania żądań.

0

@bakunet:

możesz mieć jakiś base controller do którego wstrzykiwany jest jakiś zbieracz-klikuf (singleton) i ci podpina do np. tempa czy czegoś dane

https://stackoverflow.com/a/50396968

możesz też chyba w widokach odwołać się do komponentów typu @await Component.InvokeAsync("NamingConvention1")

lub w poziomu jsa odpytac backend o te statystyki.

1

Po prostu ciasteczko.

0

Ostatecznie skłaniałem się ku rozwiązaniu w stylu:

public IActionResult Other()
        {
            int x = 0;
            if (TempData["Counter"] != null)
            {
                x = int.Parse(TempData["Counter"] as string);
            }
            x++;
            TempData["Counter"] = x.ToString();

            return View(x);
        }

Niestety, przy wielu jednoczesnych wywołaniach IActionResult i wyświetlaniach tego samego widoku w kilku zakładkach, konkurencyjne odczytywanie i zapisywanie TempData nie działa niestety tak jak się tego spodziewałem, gdzie wielokrotnie dla x odczytywana jest ta sama wartość, przez co zapisuje także kilkukrotnie tę samą wartość i nie mam jeszcze pomysłu jak ten problem przeskoczyć.

@Juhas:

Powyższy problem też się tyczy ciasteczek. Przy wielokrotnym żądaniu takiej akcji:

public ViewResult Other()
        {
            CookieOptions option = new CookieOptions();
            option.Expires = DateTime.Now.AddMinutes(10);

            int x = 0;
            if (Request.Cookies["Counter"] != null)
            {
                x = int.Parse(Request.Cookies["Counter"]);
            }
            x++;
            Response.Cookies.Append("Counter", x.ToString(), option);

            return View(x);
        }

Alternatywnym rozwiązaniem wydaje się być caching i utworzenie słownika dla każdego użytkownika. Jedynie nie mam pomysłu jak wykryć wylogowanie się / zamknięcie okna przeglądarki przez użytkownika żeby usunąć jego klucz ze słownika.

0

@bakunet:

Jedynie nie mam pomysłu jak wykryć wylogowanie się / zamknięcie okna przeglądarki przez użytkownika żeby usunąć jego klucz ze słownika.

jeżeli te dane są przypisane do usera, to nie można przy ponownym zalogowaniu ich zresetować?

0
WeiXiao napisał(a):

jeżeli te dane są przypisane do usera, to nie można przy ponownym zalogowaniu ich zresetować?

Przeszło mi to przez myśl. Lub cykliczne czyszczenie kluczy po liście zalogowanych użytkowników. Choć w tym pierwszym przypadku jak będę miał w pamięci tysiące "wiszących" kluczy użytkowników którzy się już nigdy więcej nie zalogują, to będę miał problem z pamięcią na moim bieda-serwerze :)

1

@bakunet

no to zamiast stawiać OR w Przeszło mi to przez myśl. Lub cykliczne czyszczenie kluczy to postaw AND i zastosuj te dwie metody

i kasuj tych, którzy się zalogowali lub wiszą np. 24h.

0

@WeiXiao:
Brzmi jak plan. Jak nie znajdę lepszego rozwiązania, albo ktoś inny na lepsze nie wpadnie, to wprowadzę je w życie jako najlepsze jakie mam :)

EDIT: zapomniałem, że przecież można ustawić SetSlidingExpiration dla MemoryCacheEntryOptions, co ułatwi mi życie :)

0

Ok, ostatecznie zaimplementowałem rozwiązanie, gdzie w IMemoryCache zapisuję wszystkie dane z aktywności po wysłaniu żądań do wybranych IActionResult. Dane są zapisywane przez klasę z ActionFilterAttribute. Aplikacja też uruchamia TimedHostedService z IHostedService, który cyklicznie zapisuje do DB interesujące mnie dane i czyści cache.

1 użytkowników online, w tym zalogowanych: 0, gości: 1