Search code examples
c#uwpuwp-navigation

UWP Frame is null in Frame.Navigate method


I'm implementing a function in my UWP app (LogoutUser) that logs out the user and redirects him to the LoginPage. LogoutUser has a parameter of type Page, that specifies the page from where the function has been called.

I need this parameter for calling the method "parameter".Frame.Navigate(typeof(LoginPage)) so it redirects the user to the login.

I'm calling this method when a Logout button is pressed and automatically, by a timer, if the Token that the user uses is expired.

My application can start on two different pages:

  • LoginPage if there is no token saved in a json file locally;
  • HomePage if the token is present.

My problem is that when the application starts on the HomePage and the token is expired, the function gets called with the Page being the LoginPage but the Frame being null.

I've tried fixing it by restarting the app, if the Frame is null, with the method CoreApplication.RequestRestartAsync but I don't really like this workaround and when the app is restarted it doesn't "open" automatically (It's in the taskbar but the user has to click on it twice to open it).

Function that gets called by the timer on tick. The function is inside the LoginPage and I'm passing "this" to the LogoutUser function.

private async void TimerScadenzaToken(object sender, object e)
        {
            await LoadGlobals();
            _clientAuth.DefaultRequestHeaders.Authorization = new HttpCredentialsHeaderValue("Bearer", _globals.Token.ToString());

            string checkToken = _globals.UriAuth.ToString() + "authentication";
            Uri uriAuthCheckToken = new Uri(checkToken);

            HttpResponseMessage risposta = await _clientAuth.GetAsync(uriAuthCheckToken);
            if (risposta.IsSuccessStatusCode)
            {
                return;
            }
            else
            {
                LogoutUser(this);
                timer.Stop();
                return;
            }
        }

LogoutUser function that also deletes the token from inside the json file and calls an api to delete it from database. You can see my workaround at the end of the function if the Frame is null.

public void LogoutUser(Page pageProvenienzaRichiesta)
        {
            Task asyncLoadGlobals = Task.Run(async () => await LoadGlobals());
            asyncLoadGlobals.Wait();

            string token = _globals.Token.ToString();

            dynamic tokenDinamico = new
            {
                token
            };

            string tokenDaInviare = JsonConvert.SerializeObject(tokenDinamico);
            HttpStringContent httpStringContent = new HttpStringContent(tokenDaInviare, Windows.Storage.Streams.UnicodeEncoding.Utf8, "application/json");

            string deleteToken = _globals.UriAuth.ToString() + "authentication/deleteToken";
            Uri uriAuthDeleteToken = new Uri(deleteToken);

            var eliminaToken = _clientAuth.PostAsync(uriAuthDeleteToken, httpStringContent);
            eliminaToken.AsTask().Wait();

            Task asyncDeleteJsonLocal = Task.Run(async () => await new Globals().DeleteJsonToken());
            asyncDeleteJsonLocal.Wait();

            if (pageProvenienzaRichiesta.Frame != null)
            {
                pageProvenienzaRichiesta.Frame.Navigate(typeof(LoginPage));
            }
            else
            {
                Task asyncRestart = Task.Run(async () => await Reboot());
                asyncRestart.Wait();
            }
        }

I'm calling async methods in this way because I'm calling, sorry for the repetition, the LogoutUser method inside a constructor and UWP freezes if I use .Wait().

I hope you can help me fix this either by showing me if I've done something wrong or by telling me another way of doing this.

If you need others informations ask me anything.

Thanks to anyone who is willing to help me.


Solution

  • I fixed it by removing the app restart and using this piece of code in the last else statement. You could optimize this better but I'm fine with it like this :)

    if (pageProvenienzaRichiesta.Frame != null)
                {
                    pageProvenienzaRichiesta.Frame.Navigate(typeof(LoginPage));
                }
                else
                {
                    Frame navigationFrame = Window.Current.Content as Frame;
                    navigationFrame.Navigate(typeof(LoginPage));
                }