Podany klucz nie znajduje się w słowniku

Podany klucz nie znajduje się w słowniku
BY
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 39
0

Witam,
mam problem z wylogowaniem użytkownika z aplikacji.
Mam utworzony słownik Dictionary<idSesji, User>, przy logowaniu jest sprawdzany czy dany użytkownik jest zalogowany, jeśli tak to dostaje idSesji ze słownika, jeśli nie to ma nową sesje. Jest odpalany timer który sprawdza czy czas sesji wygasnął. Jeśli tak to użytkownik jest ze słownika usuwany. Jednakże zdarza się że po sprawdzeniu czy dany użytkownik jest zalogowany to ze słownika pokazuje że tak, natomiast przy próbie ręcznego wylogowania tego użytkownika lub zalogowania ponownie wyświetla się komunikat "Podany klucz nie znajduje się w słowniku".
Usuwanie ze słownika Remove(idSesji)

WeiXiao
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 5227
2

.NET Framework? .NET Core 1? 2? 3? 5?

ASP .NET? ASP .NET Core?

To się dzieje w kontrolerze? middleware? jakimś "service"?

Słownik jest statyczny? a może z DI? a jeżeli z DI to czy jest to Singleton?

A może potrzebujesz ConcurrentDictionary?

fasadin
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 4883
2

Kula magiczna mówi że problem leży w linii 123

Pokaż kod

G1
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 507
0

To oznacza, że przy https://docs.microsoft.com/pl-pl/dotnet/api/system.collections.generic.dictionary-2.containskey?view=net-5.0 jest zwracane false i próba odczytania wartości z podanego klucza kończy się wyjątkiem. Jak nie pokażesz kodu metod odpowiedzialnych za:

  1. timer który sprawdza czy czas sesji wygasnął
  2. po sprawdzeniu czy dany użytkownik jest zalogowany
  3. przy próbie ręcznego wylogowania tego użytkownika lub zalogowania ponownie

to nic nie jesteśmy w stanie poradzić

BY
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 39
0

Webservice jest na NET Framework 3.5
Jest to stary serwis pisany pod Windows Mobile 6.5. Nie ma tu rozdzielonych warstw, wszystko pisane jednym ciągu.
Nie ma sensu tego już zmieniać ponieważ przechodzimy na Androida.
Niestety są klienci dla których trzeba to jeszcze utrzymywać

Słownik

Kopiuj
private static Dictionary<int, FntAdoConnection> userSessions = new Dictionary<int, FntAdoConnection>();

Obsługa timera

Kopiuj
        private static void onTimerEvent(object source, ElapsedEventArgs e)
        {
                    foreach (KeyValuePair<int, FntAdoConnection> us in userSessions)
                    {
                        finishNoActivityTime = us.Value.lastActivityTime;
                        finishNoActivityTime = finishNoActivityTime.AddMinutes(wc.sessionTimeOut);
                        if (finishNoActivityTime <= DateTime.Now)
                        {
                            try
                            {
                                userSessions[SPID].Close();
                                userSessions.Remove(us.Key);
                            }
                            catch { }
                        }
                    }
        }

Lista zalogowanych użytkowników

Kopiuj
        public int getListUser(out DataSet dataSet, out string errorMessage)
        {
            errorMessage = string.Empty;
            dataSet = new DataSet();
            try
            {
                DataTable dt = new DataTable();
                dataSet.Tables.Add(dt);
                dt.Clear();
                dt.Columns.Add("SPID");
                dt.Columns.Add("user");
                dt.Columns.Add("userID");
                dt.Columns.Add("lastActivityTime");
                dt.Columns.Add("UID");
                dt.Columns.Add("IP");

                foreach (KeyValuePair<int, FntAdoConnection> us in userSessions)
                {
                    DataRow _ravi = dt.NewRow();
                    _ravi["SPID"] = us.Value.SPID;
                    _ravi["user"] = us.Value.user;
                    _ravi["userID"] = us.Value.userID;
                    _ravi["lastActivityTime"] = us.Value.lastActivityTime;
                    _ravi["UID"] = us.Value.UID;
                    _ravi["IP"] = us.Value.IP;

                    dt.Rows.Add(_ravi);
                }

                return (int)answerType.ok;
            }
            catch (Exception OtherException)
            {
                errorMessage = OtherException.Message;
                dataSet = new DataSet();
                return (int)answerType.errorOther;
            }
        }

Wylogowanie użytkownika

Kopiuj
        public bool logOut(int SPID, out string errorMessage)
        {
            try
            {
                errorMessage = string.Empty;
                foreach (KeyValuePair<int, FntAdoConnection> us in userSessions)
                    if (us.Value.SPID == SPID)
                    {
                        userSessions[SPID].Close();   //  Tutaj występuje ten błąd
                        userSessions.Remove(SPID);
                        break;
                    }
                return true;
            }
            catch (Exception OtherException)
            {
                errorMessage = OtherException.Message;
                return false;
            }
        }

Logowanie

Kopiuj
        public bool logIn(string user, string password, string IP, string UID, out int SPID, out int userID, out string dt, out string errorMessage)
        {
            errorMessage = string.Empty;
            dt = DateTime.Now.ToString();
            SPID = -1;
            userID = -1;
            foreach (KeyValuePair<int, FntAdoConnection> us in userSessions)
                if (us.Value.user == user)
                {
                        SPID = us.Value.SPID;
                        userID = us.Value.userID;
                        us.Value.lastActivityTime = DateTime.Now;
                }
            FntAdoConnection adoConnection = new FntAdoConnection(wc);
            if (adoConnection.Open(out errorMessage))
            {
                if (adoConnection.logIn(user, password, out errorMessage))
                {
                    errorMessage = dt.ToString();

                    SPID = adoConnection.SPID =  adoConnection.SPID *10000 + adoConnection.userID;
                    userID = adoConnection.userID;

                    userSessions.Add(adoConnection.SPID, adoConnection);
                    userSessions[SPID].lastActivityTime = DateTime.Now;
                    userSessions[SPID].UID = UID;
                    userSessions[SPID].IP = IP;
                   
                    return true;
                }
                else return false;
            }
            else return false;
        }
VA
  • Rejestracja: dni
  • Ostatnio: dni
0

Jak często Timer odpala czyszczenie tego słownika?
Może być tak, że w czasie iterowania udaje się wyciągnąć dane przypisane do danego ID sesji ale w tym czasie akcja odpalona przez Timer czyści słownik i przy próbie zrobienia czegokolwiek na tym zasobie leci wyjątek.
Jeśli używacie statycznych kolekcji w wielowątkowym kontekście to proponuję zapoznać się z mechanizmami blokującymi takimi jak np prosty lock albo ReaderWriterLockSlim, które zablokują dostęp do danego zasobu na czas wykonywania operacji.

BY
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 39
0

@var: timer odpala się co 30s. a czas sesji pomiędzy ostatnią aktywnością jest 30min
ale to nie zmienia faktu, że pomimo czy to odpalenia timera czy też ręcznego wylogowania, użytkownik nadal figuruje na liście zalogowanych i nie można się na niego zalogować.
Taki przypadek zdarza się co prawda rzadko i jak na razie w nieznany dla mnie sposób. Blokuje to prace użytkowników.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.