2013-01-14 14 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应该提供如何处理文件被锁定并重新尝试,直到文件变得可用。

如果你的文件很小很多,你不应该经常遇到这种情况,如果有的话。