如何创建登录会话计时器为个人用户 [英] How to create Login Session Timer for individual users

查看:393
本文介绍了如何创建登录会话计时器为个人用户的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直对这个自定义计时器我为每个用户的登录会话创建。到现在为止我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 类,你可以简单地调用在通知类。

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆