2008-09-23 45 views
6

我在.net 2.0中創建了一個webservice,C#。當Web服務客戶端調用不同的方法時,我需要將一些信息記錄到文件中。使用.NET編寫Web服務中單個文件的問題

問題出現在一個用戶進程正在寫入文件並且另一個進程嘗試寫入文件時。我收到以下錯誤:

The process cannot access the file because it is being used by another process.

我試圖在C#中實現的解決方案失敗如下。

  1. 實現的單例類包含寫入文件的代碼。
  2. 使用lock語句來包裝寫入文件的代碼。
  3. 我也嘗試使用開源記錄器log4net,但它也不是一個完美的解決方案。
  4. 我知道登錄到系統事件記錄器,但我沒有這個選擇。

我想知道是否存在這樣一個問題的完美和完整的解決方案?

回答

10

鎖定可能失敗,因爲您的webservice正在由多個工作進程運行。 你可以保護與命名的互斥體,這是跨越進程共享的訪問,不像鎖你使用lock(someobject) {...}

Mutex lock = new Mutex("mymutex", false); 

lock.WaitOne(); 

// access file 

lock.ReleaseMutex(); 
+0

Mutex lockobj = new Mutex(false,「mymutex」); 將編譯 – 2009-07-07 15:32:57

+0

在創建它之前,您應該嘗試先使用該名稱打開現有的Mutex。否則,該「新的互斥體(...)」行可能會拋出異常。 我也建議使用一個try/catch/finally塊,釋放呼叫移動進入finally塊,只釋放它,如果你確實拿到了鎖。 – 2012-02-29 20:34:27

0

也許寫入一個「隊列行」來寫入文件,所以當你試圖寫入文件時,它會一直檢查文件是否被鎖定,如果是 - 它會一直等待,如果它不是鎖定 - 然後寫入它。

0

您可以將結果推送到MSMQ隊列並讓Windows服務從隊列中選取項目並記錄它們。這有點沉重,但它應該工作。

0

喬爾和查爾斯。那很快! :)

Joel:當你說「隊列線」時,你的意思是創建一個單獨的線程運行在一個循環中,以保持檢查隊列以及寫入文件時,它沒有被鎖定?

查爾斯:我知道MSMQ和窗口服務組合,但就像我說我比從Web服務:)

感謝 pradeep_tp

0

麻煩與所有內以書面文件別無選擇到目前爲止所嘗試的是多線程可以輸入代碼。 這是多個線程試圖獲取和使用文件處理程序 - 因此錯誤 - 您需要一個單獨的線程以外的工作線程來完成工作 - 單個文件句柄保持打開狀態。

可能最簡單的做法是在Global.asax的應用程序啓動過程中創建一個線程,並監聽同步的內存隊列(System.Collections.Generics.Queue)。讓線程打開並擁有文件句柄的生命週期,只有該線程可以寫入文件。

ASP中的客戶端請求會暫時鎖定隊列,將新的日誌消息推送到隊列中,然後解鎖。

記錄器線程將定期輪詢隊列中的新消息 - 當消息到達隊列時,線程將讀取並分配數據到文件中。

1

你沒有說你的web服務是如何託管的,所以我假設它在IIS中。我不認爲這個文件應該被多個進程訪問,除非你的服務在多個應用程序池中運行。不過,我想你可能會遇到這個錯誤,當一個進程中的多個線程正在嘗試寫入。

我想我會爲你自己建議的解決方案,Pradeep,建立一個單一的對象,做所有的寫入日誌文件。在那個對象裏面,我有一個Queue,所有要記錄的數據都被寫入到Queue中。我有一個單獨的線程讀取這個隊列並寫入日誌文件。在像IIS這樣的線程池環境中,創建另一個線程似乎不太好,但它只是一個......請記住,內存中的隊列不會在IIS重置後不起作用;當IIS進程關閉時,您可能會丟失一些「正在進行中」的條目。

其他替代方案當然包括使用單獨的進程(如服務)寫入文件,但這會帶來額外的部署開銷和IPC成本。如果這不適合你,請與單身人士一起去。

0

要知道我想在我的代碼做的,下面是singletone類我在C#中實現

公共密封類FileWriteTest {

private static volatile FileWriteTest instance; 

private static object syncRoot = new Object(); 

private static Queue logMessages = new Queue(); 

private static ErrorLogger oNetLogger = new ErrorLogger(); 

private FileWriteTest() { } 

public static FileWriteTest Instance 
{ 
    get 
    { 
     if (instance == null) 
     { 
      lock (syncRoot) 
      { 
       if (instance == null) 
       { 
        instance = new FileWriteTest(); 
        Thread MyThread = new Thread(new ThreadStart(StartCollectingLogs)); 
        MyThread.Start(); 

       } 
      } 
     } 

     return instance; 
    } 
} 

private static void StartCollectingLogs() 
{ 

    //Infinite loop 
    while (true) 
    { 
     cdoLogMessage objMessage = new cdoLogMessage(); 
     if (logMessages.Count != 0) 
     { 
      objMessage = (cdoLogMessage)logMessages.Dequeue(); 
      oNetLogger.WriteLog(objMessage.LogText, objMessage.SeverityLevel); 

     } 
    } 
} 

public void WriteLog(string logText, SeverityLevel errorSeverity) 
{ 
    cdoLogMessage objMessage = new cdoLogMessage(); 
    objMessage.LogText = logText; 
    objMessage.SeverityLevel = errorSeverity; 
    logMessages.Enqueue(objMessage); 

} 

}

當我在調試模式下運行此代碼(僅模擬一個用戶訪問),則會在隊列出隊的行處出現錯誤「堆棧溢出」。

注意:在上面的代碼中ErrorLogger是一個有代碼寫入文件的類。 objMessage是一個攜帶日誌消息的實體類。

+0

爲什麼要使用volatile,如果你不知道如何使用它? ; P – leppie 2008-09-23 13:59:21

0

或者,你可能想要做的錯誤記錄到數據庫中(如果你使用一個)

0

KOTH,

我已經實現互斥鎖,已經去掉了「堆棧溢出」錯誤。在我可以斷定它是否在所有情況下都工作正常之前,我還必須進行負載測試。

我在一個網站上閱讀關於Mutex objets的內容,它說Mutex會影響性能。我想通過互斥鎖瞭解一件事。

假設用戶進程1正在寫入文件,同時用戶進程2嘗試寫入同一文件。由於Process1已經對代碼塊進行了鎖定,因此Process2會在第一次嘗試之後繼續嘗試或者死掉。

感謝 pradeep_tp

0

它會等到互斥鎖的釋放....

0

Joel: When you say "queue line" do you mean creating a separate thread that runs in a loop to keep checking the queue as well as write to a file when it is not locked?

是啊,基本上我在想什麼。讓另一個線程有一個while循環,直到它可以訪問文件並保存,然後結束。

但是,您必須以第一個線程開始查找的方式首先獲取訪問權限。這就是爲什麼我說隊列。