2011-09-07 26 views
2

在我的MVC應用程序中,我有一個控制器,它創建一個Model對象的實例。在Model內,我有一個定時器,它每700ms執行一個函數。當我在我的網站中運行控制器時,即使在關閉瀏覽器窗口後,我仍然可以看到計時器正在運行。 (定時器啓動/停止串口連接,並且我有一個指示何時有通信的指示燈)。查看控制器是否仍在使用的MVC代碼

通信實際上從來沒有停止,直到我完全重新啓動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); 
} 

這裏是控制器代碼:

public ActionResult Index() { 
    CheckPulses Pulses = new CheckPulses(700); 
    return View(); 
} 

我想也許我應該只是添加一些東西到GetPulses事件,該事件發生的每一次計時器間隔到期,並檢查控制器是否仍在使用中。如果不是,請停止計時器。但是,我不知道如何寫這張支票。任何人都可以將我指向正確的方向嗎?

+0

顯示您的控制器代碼。 –

+5

您啓動了一個計時器,但從未停止它。它有沒有奇蹟它繼續運行?它不會因爲您關閉瀏覽器窗口而奇蹟般停止。 Web服務器不知道瀏覽器窗口是否打開。 –

+0

坦率地說,你不應該基於控制器的生命週期來管理定時器的生命週期,因爲它的生命週期是框架的實現細節。相反,您需要一些客戶端JavaScript,告訴串行端口控制器它仍然活着,並在客戶端停止觸發事件時拆除串行端口連接。 – Yaur

回答

-3

您可以使用JQuery + MVC停止Timer。

jQuery的可以到頁面的卸載響應事件,像這樣:

$(window).unload(function() { 
    alert('Handler for .unload() called.'); 
}); 

你可以讓你的控制器的AJAX調用。我們還需要創建一個屬性來訪問定時器。我假設你叫你的計時器物業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。你可以用純JavaScript來做到這一點。 JQuery有助於避免編寫大量繁瑣的瀏覽器兼容性代碼。 (我聽說歌劇是一個卸載部分的痛苦)

要解決潛在的瀏覽器崩潰和意外事件的問題,你可以連接你的控制器來檢查定時器是否超過了最大時間限制。

祝你好運!

來源:

JQuery Unload()

Invoking ASP.NET MVC Actions from JavaScript using jQuery

JQuery Ajax()

+0

對於這樣的系統資源來說,這是一個非常危險的方法。如果用戶瀏覽器崩潰,例如..或他們的互聯網退出,他們關閉瀏覽器..資源不會被釋放。它也不適用於不支持JavaScript的瀏覽器。 –

+0

客戶端答案不解決此服務器端問題。 –

+0

這不是2005年。非JavaScript瀏覽器正在逐漸淡出。網絡是一個JavaScript世界。這是我的意見,但支持。 @Chris沒有這方面的要求,不是客戶端解決方案。 – BentOnCoding

2

你很可能不停止或處置定時器。這將導致它不被垃圾收集,並在應用程序保持運行期間保持活動狀態。

您應該停止並在Controller的Dispose方法中處理Timer。

+0

說真的,反對票嗎?爲什麼? –

+0

問題是如何檢查控制器是否在使用中,而不是如何停止定時器和調用處置。 – BentOnCoding

+0

雖然它可能是解決我的問題,我的問題的方式..我如何使用處置方法和方法應輸入在哪裏? –

0

您有幾種選擇:

  1. 覆蓋處置控制器上的方法,並調用Pulses.Dispose()
  2. 覆蓋控制器上OnActionExecuted方法處置您的模型,並且配置
  3. 創建自定義動作過濾器並執行OnActionExecuted方法並將其分配給控制器或動作(您可以將對模型的引用放入TempData,然後在ActionFilter中檢查是否filterContext.Controller.TempData [ 「MyReferenceToModel」]!= NULL,然後用它來配置定時器)
  4. 在模型中實現IDisposable接口,並使用它裏面using語句

希望這有助於 迪馬

2

我認爲這裏的核心問題在於您瞭解控制器在使用中是什麼。

看來,如果你想象如下:

  1. 在您的網址,用戶類型和瀏覽器連接到服務器。
  2. 服務器將請求路由到MVC控制器,該控制器保持與瀏覽器的連接,並使用此連接響應每個後續請求。
  3. 用戶關閉他們的瀏覽器或導航 - 並且控制器關閉連接並處置。

但是,這並不是實際發生的情況。網絡流量通常是一系列孤立的,單獨的請求/響應配對。瀏覽器和服務器之間沒有正在進行的連接。

更正確的順序是類似如下:

  1. 用戶在你的URL類型,瀏覽器連接到服務器上的端口80(或https爲443),傳遞一個有效的HTTP請求,包含一個URL,HTTP動詞和其他信息。
  2. 您的服務器使用HTTP請求的信息路由請求特定的一段可執行代碼(在這種情況下,您的Controller的特定Action方法)。
  3. 爲了執行,服務器創建您的Controller的實例,然後使用HTTP請求的信息作爲參數來觸發它的Action方法。
  4. 您的Controller代碼執行,並且HTTP響應消息被髮送回瀏覽器。
  5. Controller.Dispose()'d由ControllerFactory

您遇到的問題不是由於您的Controller「活躍」引起的 - 因爲這不是Controller的問題。相反,您在ModelModel之間創建一個Timer,因此,它繼續在內存中生存,無法被GarbageCollection殺死。有關更多詳情,請參閱this answer

在本質上,認爲它是這樣的:

Controller充當工廠。當您撥打Index的方法時,這相當於告訴工廠「生產1 Model」。一旦Model退出工廠,工廠可以自由關閉,關掉燈,並將所有工人送回家(Controller.Dispose()'d)。

然而,Model生活在記憶中。在大多數情況下,Model可能會由於GarbageCollection超出範圍而死亡 - 但由於其中有一個活動的Timer,因此某些操作會阻止該進程執行 - 因此Model會繼續存在於您的服務器內存中,高興地在每個計時器到期時一次又一次地啓動它的代碼。

注意,這有什麼跟用戶是否仍是您的網站,或者他們的瀏覽器是否仍處於打開狀態等,與變量範圍和GarbageCollection對自然做你的服務器。現在你已經開始了一個持續的過程,直到被告知停止。

一個潛在的解決方案:

爲了解決這個問題,你可以考慮以下幾點:

  1. 創建Timer內部的Singleton對象。喜歡的東西:

    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; 
        } 
    } 
    
  2. 更改Controller到這樣的事情:

    public ActionResult Index() { 
        ConnectionManager.Start(700); 
        return View(); 
    } 
    
  3. 當你處理Timer事件到期,請檢查在多久以前lastStartedAt事件發生。如果超過X分鐘,請勿處理,並啓動ConnectionManager.Stop()

這將使您能夠保持連續活動輪詢滾動到期。換句話說 - 每次用戶請求您的頁面時,您都將刷新計時器,並確保您正在收聽。但在X分鐘後,如果沒有用戶提出請求 - 只需關閉定時器和關聯的端口即可。

+1

很好的解釋了Web應用程序的非連接性。 – Graham

相關問題