查看控制器是否仍在使用的MVC代码
本文关键字:MVC 代码 控制器 是否 | 更新日期: 2023-09-27 18:07:50
在我的MVC应用程序中,我有一个创建Model
对象实例的控制器。在Model
中,我有一个计时器,每个700ms
执行一个函数。当我在我的网站中运行控制器时,即使在我关闭浏览器窗口后,我仍然看到计时器在运行。(定时器启动/停止串口连接,我有一个灯,当有通信时指示)。
在我完全重启IIS之前,通信实际上永远不会停止。
是否有某种方法可以检查控制器是否仍在使用中,从而在控制器不再活动时停止计时器?
模型代码:
public CheckPulses(int interval) {
CheckPulsesTimer(interval);
}
public void CheckPulsesTimer(int interval) {
Timer timer = new Timer();
timer.Enabled = true;
timer.AutoReset = true;
timer.Interval = interval;
timer.Elapsed += new ElapsedEventHandler(GetPulses);
}
这里是Controller代码:
public ActionResult Index() {
CheckPulses Pulses = new CheckPulses(700);
return View();
}
我想也许我应该在GetPulses
事件中添加一些东西,每次计时器间隔到期时都会发生,并检查控制器是否仍在使用中。如果不是,停止计时器。然而,我不知道如何写那张支票。有人能给我指个方向吗?
我认为这里的核心问题是你对什么是控制器"在使用"的理解。
你似乎在想象以下内容:
- 用户输入URL,浏览器连接服务器。
- 服务器将请求路由到MVC控制器,该控制器与浏览器保持连接,并使用此连接响应每个后续请求。
- 用户关闭他们的浏览器,或者导航离开-控制器关闭连接,并处理。
更正确的顺序是这样的:
- 用户输入你的URL,浏览器通过端口80连接到你的服务器(https为443),传递一个有效的HTTP请求,包含URL, HTTP动词和其他信息。
- 您的服务器使用HTTP请求的信息将请求路由到特定的可执行代码(在这种情况下,您的
Controller
的特定Action
方法)。 - 为了执行,服务器创建一个
Controller
的实例,然后使用HTTP请求的信息作为参数,触发它的Action
方法。 - 执行
Controller
代码,并向浏览器发送HTTP响应消息。 -
Controller
是.Dispose()
'd由ControllerFactory
。
你遇到的问题不是由你的Controller
"活跃"引起的——因为这不是Controller
做的事情。相反,您在Model
中创建了Timer
,因此Model
继续存在于内存中,无法被GarbageCollection
杀死。
实际上,可以这样考虑:
你的Controller
是作为一个工厂。当你调用它的Index
方法时,相当于告诉工厂"生产1个Model
"。一旦Model
下线,工厂可以自由关闭,关灯,并让所有工人回家(Controller
是.Dispose()
'd)。
Model
仍然存在于内存中。在大多数情况下,一旦Model
超出作用域,它可能会因为GarbageCollection
而死亡——但是因为它里面有一个活动的Timer
,所以有些东西阻止了该进程的执行——所以Model
继续存在于服务器的内存中,在每次计时器到期时愉快地一次又一次地触发它的代码。
请注意,这个与用户是否还在你的网站上,或者他们的浏览器是否还打开等无关。它与变量作用域的性质和服务器上的GarbageCollection
有关。您现在已经启动了一个进程,该进程将一直持续到被告知停止为止。
一个可能的解决方案:
为了解决这个问题,你可以考虑如下:
在Singleton对象中创建
Timer
。比如:public static class ConnectionManager { private static bool initialized = false; private static DateTime lastStartedAt = DateTime.Now; private static Timer timer = null; private static void Initialize() { if (timer == null) { timer = new Timer() { AutoReset = true, }; timer.Elapsed += new ElapsedEventHandler(GetPulses); } } public static void Start(int interval) { lastStartedAt = DateTime.Now; Initialize(); // Create a timer if necessary. timer.Enabled = true; timer.Interval = interval; } public static void Stop() { timer.Enabled = false; } }
将
Controller
更改为如下内容:public ActionResult Index() { ConnectionManager.Start(700); return View(); }
当您处理
Timer
事件的过期时,检查lastStartedAt
事件发生的时间。 如果大于
X
分钟,则不处理,触发ConnectionManager.Stop()
。这将使您能够在滚动到期时保持串行活动轮询。换句话说,每次用户请求您的Index
页面时,您将刷新计时器,并确保您正在侦听。但是,在X
分钟之后,如果没有用户发出请求,您可以简单地关闭计时器和相关端口。
您可能没有停止或处置计时器。这将导致它不被垃圾收集,并在应用程序运行期间保持活动状态。
你应该在控制器的dispose方法中停止并处置Timer。
您有几个选择:
- 在控制器上重写Dispose方法,并调用脉冲。Dispose()
- 重写控制器上的onactionperformed方法并执行处置
- 创建自定义动作过滤器并实现OnActionExecuted方法并将其分配给控制器或动作。(你可以将模型的引用放入TempData中,然后在ActionFilter中检查是否filterContext.Controller。TempData["MyReferenceToModel"] = null,然后使用它来处置计时器)
- 在你的模型中实现IDisposable接口并在using语句中使用
希望这有帮助,Dima
你可以用JQuery+ MVC来停止Timer。
Jquery可以像这样响应页面的卸载事件:
$(window).unload(function() {
alert('Handler for .unload() called.');
});
可以对控制器进行ajax调用。我们还需要创建一个属性来访问计时器。我假设你把你的Timer属性命名为MyTimer
Timer MyTimer { get; set; }
所以你需要创建一个返回void并调用Timer的Stop()方法的控制器。(HttpPost)public void KillTimer(){MyTimer.Stop ();}
现在,如果您向我们之前创建的卸载事件添加一个Ajax调用,那么我们应该能够在页面关闭时终止计时器。
$.ajax(
{
type: "POST",
url: "/Home/Index",
,
success: function(result)
{
alert("Timer Closed");
},
error : function(req, status, error)
{
alert("Sorry! We could not receive your feedback at this time.");
}
});
不需要成功和错误函数。我把它们包括进来只是为了演示。我还猜你的控制器的名字是Home。如果URL不同,则需要更新URL。您可以使用纯javascript来完成此操作。JQuery帮助您避免编写大量乏味的浏览器兼容性代码。(我听说歌剧的卸货部分很痛苦)
为了解决潜在的浏览器崩溃和意外事件的问题,你可以连接你的控制器来检查计时器是否超过了最大时间限制。
祝你好运!
来源:
JQuery卸载()调用ASP。. NET MVC Actions from JavaScript using jQuery
JQuery Ajax ()