问题:
我的公司每月发布一份时事通讯,我将其托管在我们的内部网站上。我有一个供时事通讯作者上传最新版本的页面。作者上传最新的新闻通讯后,他会发送一封广播电子邮件来宣布新的新闻通讯。员工总是会检查新的时事通讯并向作者发送反馈以及需要进行的更正。
一旦作者进行了必要的更正(通常在发送广播电子邮件后一小时内),他就会重新访问我的页面并用更新的新闻通讯替换最新版本。
在更换(或更新,如果您愿意的话)新闻通讯后,任何试图访问它的人都会立即收到 500 - 内部服务器错误。
我的维护服务器的 IT 人员由于权限错误而无法删除/重命名/移动该文件,并且必须做很多复杂的事情才能删除该文件(一旦文件被删除,时事通讯的作者就可以重新 -上传更正后的副本,效果很好。
我和我的 IT 人员非常确定问题源于我试图在 IIS 主动向用户提供文件时替换该文件(我想到并认为我已编写代码以防止发生这种情况)。
运行替换的代码如下:
Protected Sub ReplaceLatestNewsletter()
Dim dr As DataRow
Dim sFile As String
Dim mFileLock As Mutex
Try
If Me.Archives.Rows.Count > 0 Then
dr = Me.Archives.Rows(0)
sFile = dr("File").ToString
If dr("Path").ToString.Length > 0 Then
mFileLock = New Mutex(True, "MyMutexToPreventReadsOnOverwrite")
Try
mFileLock.WaitOne()
System.IO.File.Delete(dr("Path").ToString)
Catch ex As Exception
lblErrs.Text = ex.ToString
Finally
mFileLock.ReleaseMutex()
End Try
End If
fuNewsletter.PostedFile.SaveAs(Server.MapPath("~/Newsletter/archives/" & sFile))
End If
Catch ex As Exception
lblErrs.Text = ex.ToString
End Try
dr = Nothing
sFile = Nothing
mFileLock = Nothing
End Sub
我以为Mutex
会解决这个问题(尽管在重新阅读文档后,我不确定我是否真的可以像我尝试的那样使用它)。对上面代码的其他评论:
-
Me.Archives
is a DataTable
存储在ViewState
-
dr("File").ToString
是文件名(无路径)
-
dr("Path").ToString
是完整的本地计算机路径和文件名(即“C:\App_Root\Newsletters\archives\20120214.pdf”)
- 新闻通讯的文件名设置为“YYYYMMDD.pdf”,其中 YYYYMMDD 是上传日期(格式化)。
无论如何,我很确定上面的代码是not对文件建立独占锁,以便可以安全地覆盖文件。
最终,我想确保发生以下情况:
- 如果 IIS 当前正在提供该文件,请等待 IIS 完成提供该文件。
- 在 IIS 再次为该文件提供服务之前,请在该文件上建立独占锁,以便其他进程、线程、用户(等)无法读取或写入该文件。
- 要么完全删除该文件并写入一个新文件来替换它,要么用新内容覆盖现有文件。
- 删除排他锁,以便用户可以再次访问该文件。
建议?
另外,我可以使用Mutex
获得 Windows 文件系统中文件的互斥锁?
预先感谢您的帮助和建议。
EDIT:
新闻通讯链接的生成方式基于物理文件名。使用的方法是:
- 获取“archives”目录下的所有PDF文件。对于每个文件:
- 从文件名中解析发布日期。
- 将日期、文件路径、文件名和每个文件的 URL 存储在
DataRow
in a DataTable
- 排序
DataTable
按日期(降序)。
- 输出第一行作为当前问题。
- 将所有后续行输出为按年和月组织的“档案”。
UPDATE:
我无法辨别该文件的所有现有请求何时完成,而是仔细查看了 @Justin 答案的第一部分(“只有当从文件读取的进程也获得相同的互斥锁。”)
这让我配置 IIS7 通过 ASP.NET 运行时服务器静态内容 https://stackoverflow.com/questions/2593932/configure-iis7-to-server-static-content-through-asp-net-runtime以及已接受答案中的链接文章。
为此,我为所有 PDF 文件实现了一个处理程序,它实现了New Mutex(True, "MyMutexToPreventReadsOnOverwrite")
确保在任何给定时间只有一个线程正在处理 PDF。
谢谢你的回答,@Justin。虽然我最终没有使用您建议的实现,但您的回答向我指出了一个可以接受的解决方案。