【问题标题】:C# - Lock file until browser is closed, user navigates away from page, or session expiresC# - 在浏览器关闭、用户离开页面或会话到期之前锁定文件
【发布时间】:2009-12-10 15:50:02
【问题描述】:

在浏览器关闭、用户离开当前页面或会话到期之前,有什么方法可以锁定文件?

我有一个 java 应用程序,它从文本文件中读取注释,并允许用户通过 java 应用程序修改或添加更多注释到 pdf。完成后,他们单击“保存”,完整的注释文件将返回到其原始数据文件。

问题是两个人可以打开同一个注释文件并执行不同的更新。然后,当每次保存时,它们会覆盖现有文件,以便只保存第二个用户的更改。

理想的解决方案是让 1 个人“签出”文件进行编辑,进行修改,直到他们关闭窗口、离开页面或会话到期,然后文件将自动“签出”在'。在 C# 中有什么方法可以做到这一点?谢谢!

【问题讨论】:

  • 听起来没有一种直接的方法可以在所有 3 个条件下工作。我可能不得不看看其他方法。感谢大家的帮助。
  • 是否可以使用 onbeforeunload 进行回发,检查目录是否有锁,并删除 c# 中的锁?这会照顾浏览器关闭和远离页面的导航。但我看不出在 onbeforeunload 中是如何发生回发的。

标签: c# asp.net file-io filelock


【解决方案1】:

没有简单的内置方法可以做到这一点,您可以在与注释文件夹相同的文件夹中创建一个 {username}.lock 文件。然后在阅读或保存之前检查目录中是否有 .lock 文件。

如果有文件告诉用户它被锁定并且不能被更新。显然,您需要确保删除 .lock 文件,否则在第一次访问后,任何人都无法访问注释文件。

【讨论】:

  • 这是我的想法,但问题是当他们的会话到期、浏览器关闭或离开页面时删除文件。他们可能会在离开页面之前执行多次保存,因此每次保存删除都不会真正起作用。或者他们可能根本不保存。必须在浏览器关闭、离开页面时以及会话到期时(以防他们让工具保持打开状态)进行捕捉。这就是我卡住的地方——尤其是会话。
  • 一个不太优雅的解决方案是定期将当前日期和时间写入锁定文件,然后检查其他人何时想要访问该文件,距当前用户有多长时间写入文件。如果超过 10 分钟,您可以认为用户已注销并解除锁定。
【解决方案2】:

如果两个用户能够编辑是应用程序的工作方式,那么为每个用户获取文件的临时副本进行编辑不是更有意义吗?

【讨论】:

  • 这就是应用程序所做的......它只是提取注释数据然后加载它。所以2个人可以同时访问。问题是,如果 2 个人更新注释(移动、删除等),您仍然不知道接受哪些更改,哪些不接受……他们可能会发生很大冲突。
  • 在这种情况下,提示最后提交更改的用户他们的更改发生冲突并需要解决它们不是更好的选择吗?
  • 这不是一个坏主意,但我不确定我们是否有时间处理复杂性。我想我们可以直接弹出它,但是拥有一个冲突管理工具太复杂了。我可能会进一步研究这条路线。
【解决方案3】:

您可以将锁定代码放在 Global.asax 文件的 Session_Start 中,并将您的释放代码放在 Session_End 方法中。但是,尝试确定用户何时真正离开会话以便在不等待会话超时的情况下触发这些事件很难检测到,但可以通过 AJAX 和一些 Javascript 来完成。

示例

protected void Application_Start()
{
    Application("AnnotationFileLocked") = False;
}
...

protected void Session_End()
{
    if ((bool)Application("AnnotationFileLocked"))
    {
         // Session("UserName") could be set on Login
         if ((string)Application("AnnotationFileLockedBy") == (string)Session("UserName"))
         {
             Application("AnnotationFileLocked") = False;
             Application.Remove("AnnotationFileLockedBy");
         }
    }
}

然后在代码中的任何位置签出文件:

public void CheckOutFile()
{
    if (!(bool)Application("AnnotationFileLocked"))
    {
        Application("AnnotationFileLocked") = True
        Application("AnnotationFileLockedBy") = (string)Session("UserName");
        // do stuff
    }
}

【讨论】:

  • 问题在于应用程序做了更多的事情。注释文件位于子目录(成百上千)中,因此检查每个子目录的锁定可能会影响性能。
  • 您可以在 Application 对象中维护一个布尔值,该值可以在 Session_Start 方法中检查,即 if (!(bool)Application("AnnotationFileLocked"))...所以在应用程序启动时将默认为 False,当第一个会话锁定时将其设置为 true,并在会话结束时将其设置为 false。
  • 这实际上看起来很容易通过会话解决问题。是否可以将其合并到 onbeforeunload 中,以便当他们离开时,我们删除锁?
  • 实际上您想要做的是有一个事件处理程序,当用户离开页面时,您可以通过 Ajax(从客户端)调用它。所以是的,它可以做到。
  • 此外,还有许多 Session_End 不会触发的实例:如果您不使用 InProc 会话(即您在农场场景中),服务器或工作进程重置等
【解决方案4】:

真的没有很好的方法来做这样的锁。尽管您可以将代码放入 Session_End 以清除锁,但不能保证触发该事件。例如,服务器可能在会话期间崩溃。您将得到一个永久锁定的文件。

由于您想要简单,您可以考虑使用基于超时的锁定。当用户 A 开始编辑文件时,他们将获得 60 分钟的独占访问权限(或您选择的任何时间段)。您在数据存储中添加了一个条目,说最近的编辑锁定是针对用户 A 的,并在下午 12:42 到期。用户 A 可以在那段时间内随意编辑。如果他之前完成了,他可以单击“完成”按钮删除锁定条目。您甚至可以给他一个“更多时间”按钮,将锁定到期时间戳更新为从现在起 60 分钟。

如果用户 B 出现并尝试编辑该文件,您的应用会检查列表并发现该文件已锁定到今天下午 12:42。如果用户 A 离开后永远无法完成,或者保存并忘记解锁,或者应用程序崩溃,您无需担心解锁或清理。用户 B 只需要等到 12:42 过去,然后您的应用程序将忽略现有的锁定条目,因为它已过期。

很多 wiki 使用与此类似的方法。它可能并不完美,但用户易于理解,并且不需要任何操作员维护。

【讨论】:

    【解决方案5】:

    您可以使用我的库从多个应用程序访问文件。

    您可以从 nuget 安装它:Install-Package Xabe.FileLock

    如果您想了解更多信息,请查看 https://github.com/tomaszzmuda/Xabe.FileLock

    ILock fileLock = new FileLock(file);
    if(fileLock.Acquire(TimeSpan.FromSeconds(15), true))
    {
        using(fileLock)
        {
            // file operations here
        }
    }
    

    fileLock.Acquire 方法只有在可以为该对象锁定文件独占时才会返回 true。 但是上传文件的应用程序也必须在文件锁定中进行。 如果对象不可访问,方法返回 false。

    因此,如果您想使用它,您可以在第一个用户打开文件时创建锁定以进行编辑,并在会话过期或用户更改页面后处理它。

    【讨论】:

      猜你喜欢
      • 2011-01-29
      • 2020-10-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多