Я работал над этим custom timer
, который я создал для каждого пользователя login session
. До сих пор мне не удавалось создать индивидуальный timers
для каждого сеанса входа в систему.
Сценарий:
Когда User1
входит в систему, timer will start counting
. Когда User2
входит в систему, таймер Use1 сбрасывает значение, такое же, как таймер для User2. Вроде у них one timer
(не индивидуальный).
Вот чего я хочу.
- когда user1 входит в систему, его таймер начинает отсчет.
- если таймер достигнет 900 секунд (15 минут), появится какое-то модальное окно, сообщающее, что его сеанс истек.
- в модальном окне будет отображаться обратный отсчет не менее 30 секунд.
- после обратного отсчета пользователь автоматически выйдет из системы
- У каждого пользователя должны быть свои таймеры
Я сделал все это, кроме последнего пункта Every user must have their own timers
Вот мой код по созданию таймера:
public class SessionTimer
{
private static Timer timer;
public static void StartTimer()
{
timer = new Timer();
timer.Interval = (double)Utility.ActivityTimerInterval();
timer.Elapsed += (s, e) => MonitorElapsedTime();
timer.Start();
}
public static void ResetTimer()
{
TimeCount = 0;
timer.Stop();
timer.Start();
}
public static int TimeCount { get; set; }
public static string ConnectionID { get; set; }
private static void MonitorElapsedTime()
{
if (TimeCount >= Utility.TimerValue())
{
timer.Stop();
Hubs.Notifier.SessionTimeOut(TimeCount);
}
else
{
Hubs.Notifier.SendElapsedTime(TimeCount);
}
TimeCount++;
}
}
После успешного входа в систему я вызову таймер для запуска
[HttpPost]
public ActionResult SignIn(LoginCredentials info)
{
// Success full login
SessionTimer.StartTimer();
}
Вот код сигнализатора на сервере:
public class SessionTimerHub : Hub
{
public void SendTimeOutNotice(int time)
{
Clients.Client(Context.ConnectionId).alertClient(time);
}
public void CheckElapsedTime(int time)
{
Clients.Client(Context.ConnectionId).sendElapsedTime(time);
}
public void UpdateConnectionID(string id)
{
SessionTimer.ConnectionID = id;
}
}
public class Notifier
{
public static void SessionTimeOut(int time)
{
var context = GlobalHost.ConnectionManager.GetHubContext<SessionTimerHub>();
context.Clients.Client(SessionTimer.ConnectionID).alertClient(time);
}
public static void SendElapsedTime(int time)
{
var context = GlobalHost.ConnectionManager.GetHubContext<SessionTimerHub>();
context.Clients.Client(SessionTimer.ConnectionID).sendElapsedTime(time);
}
}
И код jquery:
$(function () {
/////////////////////////////////////////////////// SESSION TIMER
var timer = $.connection.sessionTimerHub, $modaltimer = $('#session_timer_elapsed'), tt = null;
timer.client.alertClient = function (time) {
var $count = $modaltimer.find('.timer'), wait = 180;
$count.text(wait);
$modaltimer.modal('show');
tt = setInterval(function () {
$count.text(wait--);
if (wait < 0) {
$.post('@Url.Action("Logout", "Auth")', function () { window.location.reload(); });
window.clearInterval(tt);
}
}, 1000);
};
timer.client.sendElapsedTime = function (time) {
console.log(time);
};
$.connection.hub.start().done(function () {
timer.server.updateConnectionID($.connection.hub.id);
});
$modaltimer.on('click', '.still_here', function () {
$.post('@Url.Action("ResetTimer", "Auth")');
$modaltimer.modal('hide');
window.clearInterval(tt);
}).on('click', '.log_out', function () {
$.post('@Url.Action("Logout", "Auth")', function () { window.location.reload(); });
$modaltimer.modal('hide');
});
});
Как видите, я делаю следующее:
timer.server.updateConnectionID($.connection.hub.id);
чтобы передать идентификатор подключения, потому что я не могу получить идентификатор внутри public class Notifier
Мои неудачные решения
Я попытался поместить SessionTimer
в session
, используя dynamic
и ExpandoObject
например:
public static dynamic Data
{
get
{
#region FAILSAFE
if (HttpContext.Current.Session[datakey] == null)
{
HttpContext.Current.Session[datakey] = new ExpandoObject();
}
#endregion
return (ExpandoObject)HttpContext.Current.Session[datakey];
}
}
И это удачно разделило таймеры. Но при передаче идентификатора соединения в моей переменной expandoobject
например:
public void UpdateConnectionID(string id)
{
MyExpandoObject.MySessionTimer.ConnectionID = id;
}
он выдает исключение с нулевой ссылкой. Кажется, что мой expandoObject получает значение null при передаче данных из SignalR (просто я думаю), но я не уверен в этом.
Пожалуйста, помогите мне с этими индивидуальными таймерами и отправкой сообщений конкретным пользователям, когда их таймеры истекли.
Обратите внимание
я хочу создать таймер на стороне сервера.
Сброс таймера с сервера
Таймер должен иметь возможность сбрасываться на сервере. В этом случае я добавляю настраиваемые атрибуты на каждый AcrionReseult
e.g.:
[HttpPost]
[BasecampAuthorize]
public ActionResult LoadEmailType()
{
return Json(Enum.GetNames(typeof(EmailType)).ToList());
}
Когда пользователь проходит [BasecampAuthorize]
, это означает, что он совершил действие.
Внутри [BasecampAuthorize]
public class BasecampAuthorizeAttribute : AuthorizeAttribute
{
string url { get; set; }
public BasecampAuthorizeAttribute()
{
if (string.IsNullOrEmpty(url))
{
url = "~/SomeUrl";
}
}
public BasecampAuthorizeAttribute(string URL)
{
url = URL;
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.HttpContext.Response.Redirect(url);
}
else
{
// MUST RESET SESSION TIMER HERE
}
base.OnAuthorization(filterContext);
}
}
@ halter73 - Как здесь вызвать таймер сброса?