如何覆盖/更新IIS当前提供服务的文件

本文关键字:前提 服务 文件 IIS 更新 何覆盖 覆盖 | 更新日期: 2023-09-27 18:25:15

问题:

我的公司每月发布一份时事通讯,我在我们的内部网站上主持。我有一个页面供时事通讯的作者上传最新版本。一旦作者上传了最新的时事通讯,他就会发送一封广播电子邮件来宣布新的时讯。员工总是查看新的时事通讯,并向作者发送反馈,其中包括需要进行的更正。

一旦作者做出了必要的更正(通常在发送广播电子邮件后一小时内),他就会重新访问我的页面,并用更新的时事通讯替换最新版本。

在替换(或更新,如果你愿意的话)时事通讯后,任何试图访问它的人都会收到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是存储在ViewState中的DataTable
  • dr("File").ToString是文件名(无路径)
  • dr("Path").ToString是完整的本地机器路径和文件名(即,"C:''App_Root''Newspats''archives''20120214.pdf")
  • 时事通讯的文件名设置为"YYYYMMDD.pdf",其中YYYYMMDD是上传日期(格式化)

在任何情况下,我非常确信上面的代码是而不是在文件上建立独占锁,以便可以安全地覆盖文件。

最终,我想确保以下情况发生:

  1. 如果IIS当前正在为该文件提供服务,请等待IIS完成对该文件的服务
  2. 在IIS可以再次为该文件提供服务之前,请对该文件建立独占锁定,以便其他进程、线程、用户等都无法读取或写入该文件
  3. 完全删除文件并写入新文件以替换它,或者用新内容覆盖现有文件
  4. 删除独占锁定,以便用户可以再次访问该文件

建议?

另外,我可以使用Mutex来获得Windows文件系统中文件的互斥锁吗?

提前感谢您的帮助和建议。

编辑:

时事通讯链接的生成方式基于物理文件名。使用的方法是:

  1. 获取"归档"目录中的所有PDF文件。对于每个文件:
  2. 从文件名中分析发布日期
  3. 将日期、文件路径、文件名和每个文件的URL存储在DataRow中的DataTable
  4. 按日期(降序)对DataTable进行排序
  5. 将第一行输出为当前问题
  6. 将所有后续行输出为按年份和月份组织的"归档"

更新

为了避免无法辨别该文件的所有现有请求何时完成,我仔细查看了@Justin回答的第一部分("只有当从文件中读取的进程也获得了相同的互斥体时,你的互斥体才会起作用。")

这让我将IIS7配置为通过ASP.NET Runtime和已接受答案中的链接文章来服务器静态内容。

为此,我为所有PDF文件实现了一个处理程序,它实现了New Mutex(True, "MyMutexToPreventReadsOnOverwrite"),以确保在任何给定时间只有一个线程在处理PDF。

谢谢你的回答,贾斯汀。虽然我最终没有使用你建议的实现,但你的回答让我找到了一个可以接受的解决方案。

如何覆盖/更新IIS当前提供服务的文件

只有当从文件中读取的进程也获得了相同的互斥体时,互斥体才会起作用。提供文件的方法是什么?是使用了ASP.Net还是这只是一个静态文件?

我的工作流程会有点不同:

  1. 将新时事通讯写入文件
  2. 让IIS开始为给定的时事通讯url提供新文件而不是旧文件
  3. 在完成对旧文件的所有现有请求后删除该文件

这不需要锁定,也意味着我们不需要等待对当前文件的请求完成(如果人们继续提出新的请求,这可能需要不确定的时间)。唯一有趣的是步骤2,这将取决于文件的服务方式——最简单的方法可能是设置HTTP重定向或使用URL重写

HTTP重定向

HTTP重定向是指服务器告诉客户端在收到对给定资源的请求时寻找不同的位置,以便自动更新浏览器URL以匹配新位置。例如,如果用户请求http://server/20120221.pdf,那么他们可以被自动重定向到另一个URL,例如http://server/20120221_v2.pdf(浏览器中显示的URL会改变,但是他们需要键入的URL不会改变)。

您可以在IIS 7中使用httpRedirect配置元素来执行此操作,例如:

<configuration>
   <system.webServer>
      <httpRedirect enabled="true" exactDestination="true" httpResponseStatus="Found">
         <!-- Note that I needed to add a * in for IIS to accept the wildcard even though it isn't used in this case -->
         <add wildcard="*20120221.pdf" destination="20120221_v2.pdf" />
      </httpRedirect>
   </system.webServer>
</configuration>

链接页面显示如何从ASP.Net 更改这些设置

Url重写

或者,IIS可以设置为自动为给定URL提供不同文件的内容,而客户端(浏览器)永远不知道其中的区别。这被称为URL重写,可以在IIS中使用类似的东西来完成,但它确实需要在IIS中安装其他组件才能工作。

使用HTTP重定向可能是最简单的方法。