Need some advice or guidance. I’m new at using .NET Blazor. I’m trying to configure a sort of auto logout function for my web app. The idea is to have it spin up as a timer when the web page loads and reset the timer each time a client interaction is detected.
The idea was to embed it into the main layout (I think it’s statically rendered), but doing that does not allow me to use the OnAfterRenderAsync(bool firstRender)
. The life-cycle event never fires. From what I understand, it’s because that life-cycle event only fires for interactive components. So I cant really use that life-cycle event.
Problem I’m having, is that the JSRuntime can’t be accessed if the page has not been completely rendered. I thought I could do a Task.Wait(), but that just seems like bad practice. Other life-cycle events throw a error due to the render state.
CODE
public partial class MainLayout : IDisposable
{
private System.Timers.Timer? _timeoutTimer;
[Inject]
private IIdentityService? IdentityService { get; set; }
[Inject]
private IJSRuntime? JSRuntime { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
// set the timer to 5 minutes
_timeoutTimer = new System.Timers.Timer((int)(1 * 60 * 1000));
_timeoutTimer.Elapsed += TimeoutTimerElapsed;
_timeoutTimer.AutoReset = false;
await JSRuntime!.InvokeVoidAsync("timeOutCall", DotNetObjectReference.Create(this));
}
}
[JSInvokable]
public void TimerInterval()
{
if (_timeoutTimer is null)
ArgumentNullException.ThrowIfNull(_timeoutTimer, nameof(_timeoutTimer));
// resetting the timer if the user is in an active state & restart the timer.
_timeoutTimer.Stop();
_timeoutTimer.Start();
}
private void TimeoutTimerElapsed(object? sender, ElapsedEventArgs e)
{
InvokeAsync(async () => await IdentityService!.LogoutAsync());
}
public void Dispose()
{
if (_timeoutTimer is not null)
_timeoutTimer.Dispose();
}
}
Javascript
function timeOutCall(dotnethelper) {
var eventTypes = ['click', 'mousemove', 'keypress', 'scroll', 'touchstart', 'touchmove'];
var timer;
function resetTimeDelay() {
clearTimeout(timer);
timer = setTimeout(function () { dotnethelper.invokeMethodAsync("TimerInterval"); }, 1000); // Reset the timer after 1 second of inactivity
}
eventTypes.forEach(function (eventType) {
document.addEventListener(eventType, resetTimeDelay);
});
// Remove event listeners when the component is unloaded or the timer is reset
function removeListeners() {
eventTypes.forEach(function (eventType) {
document.removeEventListener(eventType, resetTimeDelay);
});
}
// Return a function to remove event listeners
return removeListeners;
}