我在VB.Net一個項目,需要一個全局變量(事件日誌對象的列表)全程不工作。這似乎很簡單,只需在應用程序的StartUp事件中定義變量並初始化,然後在整個應用程序中訪問它。不幸的是,這似乎只當沒有子進程工作(他們有全局變量沒有接入) - 所以我在我的頭上,如何從孩子的工作進程訪問全局變量(如果這甚至有可能的方式)。全局變量如預期
該程序將啓動幾個測試工作進程(即檢查從多個來源,網絡檢測等來自不同源的多個數據庫連接,遠程Web服務)W /進度條每個。如果在這些測試中發生錯誤,則需要記錄錯誤。 問題是,程序無法將事件記錄到Windows事件系統,因爲它不是一個管理員帳戶下運行(這樣記錄沒有可能由於MS的決定,以防止在正常的登錄用戶帳戶W/Vista中,7 ,8.10),該程序也無法登錄到一個文本文件,由於它是異步的,文件訪問爭用問題(立即記錄事件到一個文本文件將無法正常工作),所以我想記錄任何事件/內存中的錯誤(全局變量),則在所有子進程完成後,將其轉儲到日誌文件中。有意義嗎?
我創建了一個名爲AppEvent
Public Class AppEvent
Sub New()
EventTime_ = Date.Now
Level_ = EventLevel.Information
Description_ = String.Empty
Source_ = String.Empty
End Sub
Private EventTime_ As Date
Public Property EventTime() As Date
Get
Return EventTime_
End Get
Set(ByVal value As Date)
EventTime_ = value
End Set
End Property
Private Level_ As EventLevel
Public Property Level() As EventLevel
Get
Return Level_
End Get
Set(ByVal value As EventLevel)
Level_ = value
End Set
End Property
Private Description_ As String
Public Property Description() As String
Get
Return Description_
End Get
Set(ByVal value As String)
Description_ = value
End Set
End Property
Private Source_ As String
Public Property Source() As String
Get
Return Source_
End Get
Set(ByVal value As String)
Source_ = value
End Set
End Property
End Class
Public Enum EventLevel
[Information]
[Warning]
[Error]
[Critical]
[Fatal]
End Enum
類並創建只爲這一個公共變量(和初始事件添加到AppEvents列表)
Namespace My
Partial Friend Class MyApplication
'global variable here (using this for logging asynch call errors, then dumping this into a log file when all asynch calls are complete (due to file contention of log file)
Public AppEvents As New List(Of AppEvent)
Private Sub MyApplication_Startup(ByVal sender As Object, ByVal e As Microsoft.VisualBasic.ApplicationServices.StartupEventArgs) Handles Me.Startup
'create first event and add it to the global variable declared above
AppEvents.Add(New AppEvent With {.EventTime = Now, .Description = "Program Started", .Level = EventLevel.Information, .Source = "QBI"})
End Sub
End Class
End Namespace
接下來,在我的日誌類,我有一些方法用於記錄,刷新/寫入事件(s)
Public Class AppLogging
Public Shared Sub WriteEventToAppLog(evt As AppEvent)
LogDataToFile(FormatLineItem(evt.EventTime, evt.Level, evt.Description, evt.Source))
End Sub
Public Shared Sub WriteEventsToAppLog(AppEvents As List(Of AppEvent))
Dim sbEvents As New StringBuilder
If AppEvents.Count > 0 Then
For Each evt In AppEvents
sbEvents.AppendLine(FormatLineItem(evt.EventTime, evt.Level, evt.Description, evt.Source))
Next
LogDataToFile(sbEvents.ToString.TrimEnd(Environment.NewLine))
End If
End Sub
Private Shared Function FormatLineItem(eventTime As Date, eventLevel As EventLevel, eventDescr As String, eventSource As String) As String
Return String.Format("Logged On: {0} | Level: {1} | Details: {2} | Source: {3}", eventTime, System.Enum.GetName(GetType(EventLevel), eventLevel).Replace("[", "").Replace("]", ""), eventDescr, eventSource)
End Function
Private Shared Sub LogDataToFile(eventLogText As String, Optional ByVal LogFileName As String = "Error.log", Optional ByVal HeaderLine As String = "****** Application Log ******")
'log file operations
Dim LogPath As String = System.AppDomain.CurrentDomain.BaseDirectory()
If Not LogPath.EndsWith("\") Then LogPath &= "\"
LogPath &= LogFileName
Dim fm As FileMode
Try
If System.IO.File.Exists(LogPath) Then
fm = FileMode.Append
Else
fm = FileMode.Create
eventLogText = HeaderLine & Environment.NewLine & eventLogText
End If
Using fs As New FileStream(LogPath, fm, FileAccess.Write)
Using sw As New StreamWriter(fs)
sw.WriteLine(eventLogText)
End Using
End Using
My.Application.AppEvents.Clear() 'clears the global var
Catch ex As Exception
'handle this
End Try
End Sub
Public Shared Sub WriteEventToMemory(eventLevel As EventLevel, eventDescription As String, Optional eventSource As String = "")
Dim evt As New AppEvent
evt.Description = eventDescription
evt.Level = eventLevel
evt.EventTime = Now
evt.Source = eventSource
Try
My.Application.AppEvents.Add(evt)
Catch ex As Exception
Throw
End Try
End Sub
Public Shared Sub FlushEventsToLogFile()
WriteEventsToAppLog(My.Application.AppEvents)
End Sub
End Class
有幾個米方法在這裏,但每個異常處理程序中調用的方法是WriteEventToMemory(它只是將AppEvent添加到AppEvents列表中)。
一個例子測試例程/工作進程(到本地數據庫)看起來像:
#Region "local db test"
Private Sub TestLocalDBWorkerProcess_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles TestLocalDBWorkerProcess.DoWork
Me.TestLocalDBStatusMessage = TestLocalDB()
End Sub
Private Sub TestLocalDBWorkerProcess_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles TestLocalDBWorkerProcess.RunWorkerCompleted
Me.prgLocalDatabase.Style = ProgressBarStyle.Blocks
Me.prgLocalDatabase.Value = 100
If Me.ForcedCancelTestLocalDB Then
Me.lbStatus.Items.Add("Local DB Test Cancelled.")
Else
If TestLocalDBStatusMessage.Length > 0 Then
Me.lblLocalDatabaseStatus.Text = "Fail"
Me.lbStatus.Items.Add(TestLocalDBStatusMessage)
SendMessage(Me.prgLocalDatabase.Handle, 1040, 2, 0) 'changes color to red
Else
Me.lblLocalDatabaseStatus.Text = "OK"
Me.lbStatus.Items.Add("Connection to local database is good.")
Me.prgLocalDatabase.ForeColor = Color.Green
End If
End If
Me.ForcedCancelTestLocalDB = False
Me.TestLocalDBProcessing = False
ProcessesFinished()
End Sub
Private Sub StartTestLocalDB()
Me.prgLocalDatabase.Value = 0
Me.prgLocalDatabase.ForeColor = Color.FromKnownColor(KnownColor.Highlight)
Me.prgLocalDatabase.Style = ProgressBarStyle.Marquee
Me.TestLocalDBProcessing = True
Me.TestLocalDBStatusMessage = String.Empty
Me.lblLocalDatabaseStatus.Text = String.Empty
TestLocalDBWorkerProcess = New System.ComponentModel.BackgroundWorker
With TestLocalDBWorkerProcess
.WorkerReportsProgress = True
.WorkerSupportsCancellation = True
.RunWorkerAsync()
End With
End Sub
Private Function TestLocalDB() As String
Dim Statusmessage As String = String.Empty
Try
If Me.TestLocalDBWorkerProcess.CancellationPending Then
Exit Try
End If
If Not QBData.DB.TestConnection(My.Settings.DBConnStr3) Then
Throw New Exception("Unable to connect to local database!")
End If
Catch ex As Exception
Statusmessage = ex.Message
AppLogging.WriteEventToMemory(EventLevel.Fatal, ex.Message, "TestLocalDB")
End Try
Return Statusmessage
End Function
#End Region
的try-catch塊簡單地捕捉異常,並將其寫入到存儲器(I剛剛結束它在WriteEventToMemory方法,但它只是將它添加到AppEvents列表中:My.Application.AppEvents.Add(evt)
一切似乎都工作桃色,直到我注意到AppEvents的計數是(1)後啓動事件,然後它的計數是來自任何子進程的(0),最後,計數是(1)當列表被轉儲到錯誤日誌文件(僅限於第一個活動就是在那裏)。這顯然就像AppEvents變量有多個版本一樣。
****** Application Log ******
Logged On: 10/7/2016 6:01:45 PM | Level: Information | Details: Program Started | Source: QBI
只有第一個事件顯示出來,而不是(它們被添加,沒有空裁判異常或任何例外 - 如幻影)的其他事件。任何添加到主線程上的全局變量的事件都會保留(最終會被記錄)。所以這顯然是一個多線程問題(從未在Windows應用程序中嘗試過)。 關於如何補救的任何想法?
那是一個很多代碼。除了'MyApplication_Startup',我無法看到你在列表中添加什麼東西。請參閱[MCVE] – Plutonix
WriteEventToMemory方法是將AppEvent添加到AppEvents列表的唯一位置。 我真的不能做一個mutlthreaded示例比任何更小(除非我只是刪除) – MC9000
我剛剛遇到了解決方案 - 全局變量不是一個線程安全的即使它的工作。 http://stackoverflow.com/questions/7563825/global-variable-in-asp-net#7564075 – MC9000