天天看點

WPF 降低.net framework到4.01. 問題背景2.解決問題3. 問題原因4. 解決問題

原文: WPF 降低.net framework到4.0

1. 問題背景

由于xp系統上面最高隻能安裝.net framework 4.0,是以公司項目需要将原來項目的.net framework版本降低到4.0,具體的降版本很簡單,隻要把項目屬性中的目标架構改成4.0,編譯一下,解決一下出現的問題就可以了。但是在打包同僚電腦上,登入界面都正常出來了,但是登入進去後,直接奔潰了。

2.解決問題

一開始檢查了項目及其依賴檔案的.net framework的版本,都是4.0,直接運作的是生成檔案,中間沒有更改任何檔案,是以開始以下解決問題的道路。

(1)查找奔潰的dmp檔案

程式的奔潰檔案一般都在C:\Users\XXX\AppData\Local\CrashDumps目錄下面,可惜的是,在同僚電腦上面,沒有發現崩潰檔案。

(2)查找系統的事件日志

選中桌面計算機,右擊,選擇管理,在系統工具-》事件檢視器-》自定義視圖-》.NET Runtime, 輕按兩下,找到奔潰時間點的日志,找到如下的錯誤資訊:

Application: XXXX.exe

Framework Version: v4.0.30319

Description: The process was terminated due to an unhandled exception.

Exception Info: System.AggregateException

Stack:

   at System.Threading.Tasks.TaskExceptionHolder.Finalize()

因為項目中用到Task的地方隻有一處,是以注釋掉這段代碼,在同僚電腦上面試了一下,果然OK,程式正常運作。下面就是要看看具體是什麼原因造成這個異常。

3. 問題原因

在stackoverflow上提到了

這個問題的原因

If you create a Task, and you don't ever call 

task.Wait()

 or try to retrieve the result of a 

Task<T>

, when the task is collected by the garbage collector, it will tear down your application during finalization. For details, see MSDN's page on  Exception Handling in the TPL

.

The best option here is to "handle" the exception. 

根據上面的英文,我的了解是:當你建立一個Task,沒有調用過task.Wait()或者沒有擷取它的執行結果,(如果Task中出現了未處理的異常),當這個Task被GC回收時,在GC finalization階段,會讓目前應用程式崩潰。

進一步看MSDN中的

Exception Handling (Task Parallel Library)

"Unhandled exceptions that are thrown by user code that is running inside a task are propagated back to the joining thread. ···Exceptions are propagated when you use one of the static or instance Task.Wait or Task(Of TResult).Wait methods···"

翻譯:在一個task中運作的代碼抛出的未處理異常會被回傳給(建立該task的)主線程。···當你調用Task.Wait時,異常才會被回傳(給主線程)。

分析:當我們遇到的情況是沒調用Task.Wait,也就是異常沒有被回傳給主線程。下面的這句就提到了這個:

"If you do not wait on a task that propagates an exception, or access its Exception property, the exception is escalated according to the .NET exception policy when the task is garbage-collected."

譯:如果你在一個task中沒有等待異常被傳播,或者通路它的異步特性,在task被GC回收時,該異常會遵循.NET異常政策被逐漸更新。

分析:逐漸更新的後果就是目前應用程式程序崩潰,對于ASP.NET程式來說,就是應用程式池崩潰。

4. 解決問題

最簡單的方法就是捕獲一下task中的異常,參考msdn中的代碼大概如下:

1 var task1 = Task.Run(() => { throw new CustomException("task1 faulted."); }).ContinueWith( t => { Console.WriteLine("{0}: {1}", t.Exception.InnerException.GetType().Name, t.Exception.InnerException.Message); }, TaskContinuationOptions.OnlyOnFaulted); Thread.Sleep(500);