I am working on a Xamarin Apps. One of the requirements is to logout user after certain period of time. I put a timer that runs every 30 mins to tell the user that his session expired and give him option to continue his session or logout. If he decided to continue his session, the timer will continue to run every 30 minutes, but if he decided to end his session the timer will stop.
The timer in Xamarin doesn't honor the time you set on the StartTimer because it runs even before the 30 minutes.
App.xaml.cs
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new LoginPage());
}
LoginPage.xaml.cs
public LoginPage()
{
InitializeComponent();
CheckUserLoginStatus();
}
public async void CheckUserLoginStatus()
{
var msalService = new MsalAuthService();
if (await msalService.SignInAsync())
{
Settings.UserLastLogin = DateTime.Now;
App.Current.MainPage = new Master();
}
}
MsalAuthService.cs
public async Task<bool> SignInAsync()
{
try
{
// login logic here
//after successfull login start timer
Device.StartTimer(new TimeSpan(0, 30, 0), () =>
{
// do something every 30 minutes
Device.BeginInvokeOnMainThread(async () =>
{
// interact with UI elements
await AutoLogout();
});
var accessToken = ApplicationPropertyProvider.GetProperty<string>(Commons.AUTH_TOKEN);
return !string.IsNullOrEmpty(accessToken);
});
Application.Current.Properties["USERLOGINDATE"] = DateTime.Now;
return !string.IsNullOrEmpty(accessToken);
}
return true;
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
return false;
}
}
CodePudding user response:
Its possible to periodically interact with user, without a timer:
using System.Diagnostics;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace XFSOAnswers
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class PeriodicInteractPage : ContentPage
{
public PeriodicInteractPage()
{
InitializeComponent();
StartPeriodicTask(5, GetUserConfirmation, Done);
}
delegate Task<bool> TaskBoolDeleg();
delegate Task TaskDeleg();
private void StartPeriodicTask(float seconds, TaskBoolDeleg periodicTask, TaskDeleg doneTask)
{
// On MainThread, so can interact with user.
// "async" "await Delay" ensures UI is not blocked until time is up.
Device.BeginInvokeOnMainThread(async () =>
{
bool alive = true;
while (alive)
{
await Task.Delay((int)(1000 * seconds));
alive = await periodicTask();
}
await doneTask();
});
}
private async Task<bool> GetUserConfirmation()
{
// Block UI until user responds.
bool answer = await DisplayAlert("", "Are you still there?", "Yes", "No");
Debug.WriteLine($"--- Still there: {answer} ---");
return answer;
}
private async Task Done()
{
Debug.WriteLine($"--- DONE ---");
await DisplayAlert("", "Logout", "OK");
}
}
}
StartPeriodicTask(5, GetUserConfirmation, Done);
will call GetUserConfirmation
after 5 seconds. Increase as desired.
If user responds "Yes", then the time delay starts again.
If user responds "No", then loop exits, Done
runs.
CREDIT: Based loosely on the "timerless" approach in https://stackoverflow.com/a/45364589/199364.