如何创建登录会话计时器为个人用户 [英] How to create Login Session Timer for individual users
问题描述
我一直对这个自定义计时器
我为每个用户的登录会话创建
。到现在为止我was'nt能够使个人计时器
每个登录会话。
I've been working on this custom timer
I created for each user's login session
. Until now I was'nt able to make an individual timers
for each login session.
情景:
在用户1
登录时,计时器将开始计数
。当用户2
登录,USE1的计时器将重置价值是一样的定时器用户2。
他们似乎有一个计时器
(不单独)。
When User1
logs in, the timer will start counting
. When User2
logs in, the timer of Use1 will reset the value is same as the timer for User2.
It seems that they have one timer
(not individual).
下面是我希望发生的。
Here is what I want to happen.
- 在当前的user1登录时,他的计时器便会开始计数。
- 如果计时器达到900秒(15分钟),它会弹出一些模式框,告诉他的会话都有超时。
- 的模式将呈现倒计时为至少30秒
- 倒计数后,用户将被自动注销
- 每个用户都必须有自己的计时器
我已经做了所有这些,除了最后一个项目每个用户都必须有自己的计时器
I have done all of these except the last item Every user must have their own timers
下面是创建一个计时器我的code:
Here is my code on creating a timer:
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++;
}
}
成功登录后,我会打电话给定时器启动</ P>
After a successful login, I'm going to call the timer to start
[HttpPost]
public ActionResult SignIn(LoginCredentials info)
{
// Success full login
SessionTimer.StartTimer();
}
下面是关于服务器的signalr code:
Here is the signalr code on server:
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的code:
And the jquery code:
$(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');
});
});
正如你可以看到我在做这样的:
As you can see I'm doing this:
timer.server.updateConnectionID($.connection.hub.id);
通过连接ID,因为我不能让里面的ID 公共类通知
我失败的解决方案
我试过使用把 SessionTimer
在会议
动态
和 ExpandoObject
结果
例如:
I tried putting the SessionTimer
in a session
using dynamic
and ExpandoObject
e.g:
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变量结果的连接ID时
例如:
And it successfully separated the timers. But when passing the connection id on my expandoobject variable
e.g:
public void UpdateConnectionID(string id)
{
MyExpandoObject.MySessionTimer.ConnectionID = id;
}
它抛出空引用异常。似乎从SignalR(只是我的想法)传递数据时,我expandoObject越来越空,但我不知道该。
it throws null reference exception. It seems that my expandoObject is getting null when passing data from SignalR (Just my thinking), but I'm not sure for that.
请帮我这个人计时器和当他们的计时器已经过去了发送消息给特定用户。
Please help me with this individual timers and sending message to specific users when their timers has elapsed.
请注意结果
我想创建一个在服务器端的计时器。
Please note
I want to create the timer on Server Side.
重置从服务器定时
定时器必须能够在服务器上复位。在这种情况下,我把每一个自定义属性 AcrionReseult
The timer must be able to reset on server. In this case I put custom attributes on every AcrionReseult
例如:
[HttpPost]
[BasecampAuthorize]
public ActionResult LoadEmailType()
{
return Json(Enum.GetNames(typeof(EmailType)).ToList());
}
当用户通过 [BasecampAuthorize]
这意味着他做了一个活动。结果
在 [BasecampAuthorize]
When the user passes [BasecampAuthorize]
it means he made an activity.
Inside [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 - ?我怎么可以在这里所说的复位定时器
@halter73 - How can I call the reset timer here?
推荐答案
您的问题是,你只能有一个静态的定时器变量是在整个应用程序域共享劲儿实例。在ASP.NET中,AppDomain的是每个Web应用程序不是每个用户。您可以使用一个静态变量,但该变量应该是一个集合持有每一个的ConnectionId唯一计时器。如果你向外扩展的背后负载平衡器或重新启动IIS这显然会创建一个新的AppDomain应用这将打破。
Your problem is that you only have one static timer variable which is signle instance shared across an entire AppDomain. In ASP.NET, AppDomain's are per web application not per user. You can use a static variable, but that variable should be a collection holding a unique Timer for each connectionId. This will break down if you scale out behind a load balancer or IIS restarts the application which will obviously create a new AppDomain.
public class SessionTimer : IDisposable
{
public static readonly ConcurrentDictionary<string, SessionTimer> Timers;
private readonly Timer timer;
static SessionTimer()
{
Timers = new ConcurrentDictionary<string, SessionTimer>();
}
private SessionTimer(string connectionID)
{
ConnectionID = connectionID;
timer = new Timer();
timer.Interval = (double)Utility.ActivityTimerInterval();
timer.Elapsed += (s, e) => MonitorElapsedTime();
timer.Start();
}
private int TimeCount { get; set; }
private string ConnectionID { get; set; }
public static void StartTimer(string connectionID)
{
var newTimer = new SessionTimer(connectionID);
if (!Timers.TryAdd(connectionID, newTimer))
{
newTimer.Dispose();
}
}
public static void StopTimer(string connectionID)
{
SessionTimer oldTimer;
if (Timers.TryRemove(connectionID, out oldTimer))
{
oldTimer.Dispose();
}
}
public void ResetTimer()
{
TimeCount = 0;
timer.Stop();
timer.Start();
}
public override Dispose()
{
// Stop might not be necessary since we call Dispose
timer.Stop();
timer.Dispose();
}
private void MonitorElapsedTime()
{
if (TimeCount >= Utility.TimerValue())
{
StopTimer(ConnectionID);
Hubs.Notifier.SessionTimeOut(ConnectionID, TimeCount);
}
else
{
Hubs.Notifier.SendElapsedTime(ConnectionID, TimeCount);
}
TimeCount++;
}
}
既然你店内的连接ID的 SessionTimer
类,你可以简单地调用在通知方法时,将它作为一个参数code>类。
Since you store the connection id inside the SessionTimer
class, you can simply pass it in as a parameter when calling methods in the Notifier
class.
public static class Notifier
{
private static context = GlobalHost.ConnectionManager.GetHubContext<SessionTimerHub>();
public static void SessionTimeOut(string connectionID, int time)
{
context.Clients.Client(connectionID).alertClient(time);
}
public static void SendElapsedTime(string connectionID, int time)
{
context.Clients.Client(connectionID).sendElapsedTime(time);
}
}
您不需要 SendTimeOutNotice
或 CheckElapsedTime
,因为你在呼唤你的<$ c中的客户端的方法$ C>通知类。 UpdateConnectionID
可以通过 OnConnected
所取代。
You don't need the SendTimeOutNotice
or CheckElapsedTime
since you are calling the client methods in your Notifier
class. UpdateConnectionID
can be replaced by OnConnected
.
public class SessionTimerHub : Hub
{
public override Task OnConnected()
{
SessionTimer.StartTimer(Context.ConnectionId);
return base.OnConnected();
}
public override Task OnDisconnected()
{
SessionTimer.StopTimer(Context.ConnectionId);
return base.OnDisconnected();
}
public void ResetTimer()
{
SessionTimer.Timers[Context.ConnectionId].ResetTimer();
}
}
您应该将轮毂内可以创建 SessionTimers
这样你就可以将其与连接ID关联。您可以在 OnConnected
像上面这样做,但是这意味着,一旦你登录你应该只启动SignalR连接,你真的想开始新的 SessionTimer
该连接。它还可以帮助有 ResetTimer
的轮毂让你有客户端的连接ID。或者,您可以从 $。connection.hub.id
获取客户端的连接ID和张贴。
You should be creating your SessionTimers
inside your hub so you can associate it with your connection id. You can do this in OnConnected
like above, but that means that you should only start your SignalR connection once you've logged in and you actually want to start your SessionTimer
for that connection. It also helps to have ResetTimer
on the hub so you have the client's connection id. Alternatively, you could get the connection id on the client from $.connection.hub.id
and post it.
$.connection.hub.start().done(function () {
$modaltimer.on('click', '.still_here', function () {
timer.server.resetTimer();
$.post('@Url.Action("ResetTimer", "Auth")');
$modaltimer.modal('hide');
window.clearInterval(tt);
});
});
编辑:
如果由于某种原因, SessionTimerHub.ResetTimer
被扔 KeyNotFoundException
(如果你正在调用哪一个不应该发生 timer.server.resetTimer
在 $。connection.hub.start()。完成
火灾),你可以做以下内容:
If for some reason SessionTimerHub.ResetTimer
is throwing a KeyNotFoundException
(which shouldn't happen if you are calling timer.server.resetTimer
after $.connection.hub.start().done
fires), you could do the following:
public void ResetTimer()
{
SessionTimer timer;
if (SessionTimer.Timers.TryGetValue(Context.ConnectionId, out timer))
{
timer.ResetTimer();
}
else
{
SessionTimer.StartTimer(Context.ConnectionId);
}
}
如果由于某种原因,IIS是重新启动您的应用程序,你可能要在 SessionTimerHub.OnReconnected
添加这个,因为客户端将重新连接,但你的静态SessionTimer.Timers将被重置,并与所有的SessionTimers将不复存在。
If for some reason IIS is restarting your application you may want to add this in SessionTimerHub.OnReconnected
since clients will reconnect but your static SessionTimer.Timers will be reset and and all your SessionTimers will be gone.
public override Task OnReconnected()
{
if (!SessionTimer.Timers.ContainsKey(Context.ConnectionId))
{
SessionTimer.StartTimer(Context.ConnectionId);
}
return base.OnReconnected();
}
您通常不会调用 SessionTimerHub.ResetTimer()
在C#中吗?
You aren't ever calling SessionTimerHub.ResetTimer()
in C# right?
这篇关于如何创建登录会话计时器为个人用户的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!