2013-01-14 47 views
1

我們有一個網站應用程序,它充當表單設計者。鎖定Web應用程序中的XML文件

表單數據存儲在XML文件中。每個表單都有它自己的xml文件。

當我編輯表單時,我基本上重新創建了XML文件。

public void Save(Guid form_Id, IEnumerable<FormData> formData) 
{ 
    XDocument doc = new XDocument(); 
    XElement formsDataElement = new XElement("FormsData"); 
    doc.Add(formsDataElement); 
    foreach (FormData data in formData) 
    { 
     formsDataElement.Add(new XElement("FormData", 
           new XAttribute("Id", data.Id) 
           new XAttribute("Name", data.Name) 
           // other attributes 
          )); 
    } 

    doc.Save(formXMLFilePath); 
} 

這很好,但我想確保兩個用戶不會同時更新XML文件。我想以某種方式鎖定它。

我怎樣才能單獨鎖定每個文件的保存過程?

我可以像下面那樣鎖定Save函數,但是這會鎖定所有用戶,即使它們保存了不同的XML文件。

private static readonly object _lock = new object(); 
public void Save(Guid form_Id, IEnumerable<FormData> formData) 
{ 
    lock(_lock) 
    { 
     XDocument doc = new XDocument(); 
     foreach (FormData data in formData) 
     { 
      // Code 
     } 

     doc.Save(formXMLFilePath); 
    } 
} 
+0

你說「文件」。您是否將XML文檔存儲到Windows文件系統? –

+0

是的,我將xml文件保存在硬盤上。 – Catalin

回答

1

嘗試是這樣的:

FileStream file = new FileStream(formXMLFilePath,FileMode.Create,FileAccress.Write,FileShare.None); 

try { 
    doc.Save(file); 
} finally { 
    file.Close(); 
} 

這將使用FileStream,我們提供一個FileShare模式。在我們的情況下,我們只有鎖定文件,只有我們可以寫入它。

但是,這只是意味着後續寫入操作會因鎖定而失敗。

爲了解決這個問題,我傾向於有一個隊列和一個單獨的線程,只有工作是處理隊列並寫入文件系統。

但是,另一種解決方案是簡單地嘗試和訪問該文件,如果失敗,稍等一會然後再試一次。這將讓你做一個類似於lock,在這裏等到它可以訪問,然後進入:

private static bool IsLocked(string fileName) 
{ 
    if (!File.Exists(fileName)) return false; 

    try { 
     FileStream file = new FileStream(fileName,FileMode.Open,FileAccess.Write,FileShare.None); 

     try { 
      return false; 
     } finally { 
      file.Close(); 
     } 
    } catch (IOException) { 
     return true; 
    } 
} 

public void Save(Guid form_Id, IEnumerable<FormData> formData) 
{ 
    while (IsLocked(formXMLFilePath)) Thread.Sleep(100); 

    FileStream file = new FileStream(formXMLFilePath,FileMode.Create,FileAccress.Write,FileShare.None); 

    try { 
     doc.Save(file); 
    } finally { 
     file.Close(); 
    } 
} 
+0

看起來完全像我需要的!這將阻止文件,即使我打開它而不使用FileStream,對不對? (例如:XDocument doc = new XDocument(formXMLFilePath))。如果用戶試圖打開它並被阻止,線程會一直等到文件被釋放或者會引發錯誤? – Catalin

+0

它不會等待。它會失敗。您可以指定FileShare.Read以允許只讀訪問。你將需要編組文件的訪問權限,否則你會打鎖並得到一個異常。這不是線程鎖意義上的鎖。 – Lloyd

+0

你能告訴我一個簡單的例子,我怎樣才能創建一個單獨的線程,請? – Catalin

0

你沒有關閉打開您的XML文件後,您的XML文件的連接。所以我認爲你需要在你的函數結束時先關閉你的連接。

您可以使用此

filename.Close(); 

我希望這將有助於你

+0

XDocument沒有Close()或Dispose()方法 – Catalin

+0

這裏的doc表示文件名。看到更新 –

2

爲了防止被同時寫入文件時,XDocument.Save方法在內部使用下面的構造函數創建一個FileStream

new FileStream(
    outputFileName, 
    FileMode.Create, 
    FileAccess.Write, 
    FileShare.Read, 
    0x1000, 
    UseAsync) 

選項FileShare.Read可防止多個寫入同時發生。如果你試圖同時執行兩個寫操作,你會拋出一個IOException

您可能想編寫一些代碼來處理這種可能性。這個答案https://stackoverflow.com/a/50800/138578應該提供如何處理文件被鎖定並重新嘗試,直到文件變得可用。

如果你的文件很小很多,你不應該經常遇到這種情況,如果有的話。