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

时间:2012-02-21 16:19:27

标签: c# asp.net vb.net iis-7

问题:

我公司发布了一份月刊,我在内部网站上发布。我有一个页面供新闻稿的作者上传最新版本。一旦作者上传了最新的时事通讯,他就会发送一封广播电子邮件来宣布新的时事通讯。员工总是查看新的简报并将反馈发送给作者,并进行必要的更正。

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

在更新(或更新,如果你愿意)新闻通讯之后,任何试图访问它的人都会立即获得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是存储在DataTable
  • 中的ViewState
  • dr("File").ToString是文件名(无路径)
  • dr("Path").ToString是完整的本地计算机路径和文件名(即'C:\ App_Root \ Newsletters \ archives \ 20120214.pdf')
  • 新闻简报的文件名设置为“YYYYMMDD.pdf”,其中YYYYMMDD是上传的日期(格式化)。

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

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

  1. 如果IIS当前正在为该文件提供服务,请等待IIS完成服务。
  2. 在IIS再次提供文件之前,请在文件上建立一个独占锁,以便其他进程,线程,用户(等)不能读取或写入该文件。
  3. 完全删除文件并编写新文件以替换它或用新内容覆盖现有文件。
  4. 删除独占锁,以便用户可以再次访问该文件。
  5. 建议?

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

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

    修改

    生成简报的链接的方式基于物理文件名。使用的方法是:

    1. 获取“archives”目录中的所有PDF文件。对于每个文件:
    2. 从文件名解析发布日期。
    3. 将日期,文件路径,文件名和网址存储到DataRow
    4. DataTable中的每个文件中
    5. 按日期排序DataTable(降序)。
    6. 将第一行输出为当前问题。
    7. 将所有后续行输出为按年和月组织的“档案”。
    8. 更新

      代替无法辨别该文件的所有现有请求何时完成,我仔细研究了@Justin的答案的第一部分(“你的互斥体只会在从文件也获得相同的互斥锁。“)

      这导致我Configure IIS7 to server static content through ASP.NET Runtime以及已接受答案中的链接文章。

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

      谢谢你回答,@ Justin。虽然我没有使用你建议的实现,但你的答案指向了我可接受的解决方案。

1 个答案:

答案 0 :(得分:3)

只有从文件中读取的进程也获得相同的互斥锁时,您的互斥锁才会生效。用于提供文件的方法是什么?是使用ASP.Net还是仅仅是一个静态文件?

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

  1. 将新简报写入文件
  2. 让IIS开始提供新文件,而不是给定的新闻稿网址
  3. 的旧文件
  4. 完成对该文件的所有现有请求后删除旧文件
  5. 这不需要锁定,也意味着我们不需要等待完成当前文件的请求(如果人们继续发出新请求,这可能会花费无限的时间)。唯一有趣的是第2步,它将取决于文件的服务方式 - 最简单的方法可能是设置HTTP重定向或使用URL重写

    HTTP重定向

    HTTP重定向是服务器在获取给定资源的请求时告诉客户端查看其他位置的位置,以便自动更新浏览器URL以匹配新位置。例如,如果用户请求http://server/20120221.pdf,那么他们可以自动重定向到另一个URL,例如http://server/20120221_v2.pdf(浏览器中显示的URL会发生变化,但是他们需要输入的URL不会)。

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

    <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

    更改这些设置

    网址重写

    另外,IIS可以设置为自动提供给定URL的不同文件的内容,而客户端(浏览器)不知道其中的差异。这称为URL重写,可以使用this之类的东西在IIS中完成,但它确实需要在IIS上安装其他组件才能工作。

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