1

我正在开发一个我继承的网站,该网站是用 ASP.Net 构建的,我只是稍微熟悉。其中一个页面允许链接到文档(word 或 pdf),单击该链接会提示用户保存或打开文件,但不会显示文件的真实路径。通过这种方式,它可以防止用户将 url 粘贴到文件中 - 该链接指向一个 aspx 文件,该文件检查有效会话,然后检索该文件。

无论如何,因为有很多遗留代码,我还需要使用一堆静态 htm 文件来执行此操作,但是这些文件需要显示而不是提示用户保存它们,这就是现在发生的情况。我尝试将内容类型更改为 application/text、application/html、text/html 等,但没有成功,然后尝试添加 content-disposition inline 的响应标头。当我这样做、构建并尝试链接到文件时,我得到了几个运行时异常:

[FormatException: Input string was not in a correct format.]
Microsoft.VisualBasic.CompilerServices.Conversions.ParseDecimal(String Value, NumberFormatInfo NumberFormat) +206
Microsoft.VisualBasic.CompilerServices.Conversions.ToLong(String Value) +110

[InvalidCastException: Conversion from string "inline; filename=\" + myFile + " to type  'Long' is not valid.]
Microsoft.VisualBasic.CompilerServices.Conversions.ToLong(String Value) +428
cmswebasp.CMSModdoclinks.DownloadFile(String file) +1704
cmswebasp.CMSModdoclinks.Page_Load(Object sender, EventArgs e) +625
System.Web.UI.Control.OnLoad(EventArgs e) +99
System.Web.UI.Control.LoadRecursive() +50
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +627

这是页面中的一段代码:

Response.AddHeader("Content-Disposition", "inline; filename=" & file)


Dim fi As New FileInfo(myFile)
Response.AddHeader("Content-Length", fi.Length)

Dim contentType As String = ""
Dim fileExt As String = file.Split(".")(1)

Select Case fileExt

Case "htm"
contentType = "application/text"
Case Else
contentType = "application/octet-stream"
End Select

Response.ContentType = contentType
Response.WriteFile(myFile)

我是否必须对 htmlwriter 对象或其他东西做些什么?我不能让它打开一个显示文件的新浏览器窗口,或者如果以这种方式使用它是否必须提示用户?

4

3 回答 3

2

废弃整页 (.aspx) 方法,而不是使用通用处理程序 (.ashx)。.aspx 页面将执行大量内置加载来初始化通常在 ASP.NET 网页中使用的所有状态,而通用处理程序仅初始化最低限度以将输出发送回客户端.

使用通用处理程序时,您还需要实现System.Web.SessionState.IRequiresSessionState以获取会话状态,因为默认情况下它不会加载会话状态。

一个例子:

Public Class FileWrapper
    Implements System.Web.IHttpHandler, System.Web.SessionState.IRequiresSessionState

    Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
        ' Validate session...

        ' Set output content type based on extension of requested file
        Dim fileName As String = context.Request.QueryString("file")
        Dim fileExt As String = fileName.Split("."c)(1).ToLowerInvariant()
        Select Case fileExt
            Case "htm", "html"
                context.Response.ContentType = System.Net.Mime.MediaTypeNames.Text.Html
            Case Else
                context.Response.AddHeader("Content-Disposition", "attachment; filename=" & fileName)
                context.Response.ContentType = System.Net.Mime.MediaTypeNames.Application.Octet
        End Select
        context.Response.WriteFile(fileName)
    End Sub

    ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
        Get
            Return False
        End Get
    End Property

End Class

注意:如果托管在 IIS 7 上,您将需要从中删除任何<httpHandler>注册<system.web>并将它们<handler>注册为<system.webServer>.

例如(根据需要正确使用您的命名空间):

<system.webServer>
  <!-- For IIS 7 -->
  <handlers>
    <add name="FileWrapperHandler" path="FileWrapper.ashx" verb="*" type="MyNamespace.FileWrapper"/>
  </handlers>
</system.webServer>

另一个注意事项:如果您正在使用集成管道(IIS 7 的默认设置)为 IIS 7 主机进行开发,那么我建议您为您的 Web 项目使用(并在必要时安装)IIS Express 选项。这可以在您的 Web 项目的属性中找到,从左侧开始的 Web 选项卡,然后在服务器部分中,选择使用本地 IIS Web 服务器单选按钮,然后选中下面的使用 IIS Express。

使用 IIS Express

这将使您的开发环境与您的生产环境的行为方式更加同步。

于 2012-04-18T20:53:12.917 回答
0

当您调用Response.WriteFile(). 当客户端收到它时,找出实际的内容类型标头是什么。 如果您查看其“网络”选项卡,Firebug会告诉您。

如果是这种情况,请Response.ContentType在调用后尝试设置Response.WriteFile()。或者,您可以尝试将文件读入字符串并使用Response.Write()而不是WriteFile.

于 2012-04-18T20:37:52.773 回答
0

经过一番讨论后,看起来您可能最好使用 lobotomized Page,而不是通用处理程序,因为用户可能通过 Word 文档中的链接或浏览器外部的其他来源访问该站点。

我们发现在这种情况下,aspx 页面能够恢复会话,而 ashx 则不能。因此,我提供了一个 aspx 解决方案的代码:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    ' Validate session...

    ' Set output content type based on extension of requested file
    Dim fileName As String = Request.QueryString("file")
    Dim fileExt As String = fileName.Split("."c)(1).ToLowerInvariant()
    Select Case fileExt
        Case "htm", "html"
            Response.ContentType = System.Net.Mime.MediaTypeNames.Text.Html
        Case Else
            Response.ClearHeaders()
            Response.AppendHeader("Content-Disposition", "attachment; filename=" & fileName)
            Response.ContentType = System.Net.Mime.MediaTypeNames.Application.Octet
    End Select
    Response.WriteFile(fileName)
    Response.Flush()
    Response.Close()
End Sub

放置在 aspx 标记本身中的任何内容都无关紧要,因为无论如何都不会呈现这些内容。

请注意,这可能会导致 Web 主机上的一些日志条目尝试“访问已关闭的流”,因为我们已经关闭了响应流,但页面将继续照常处理。这是实质上劫持正常页面流所要付出的代价之一。

于 2012-05-09T19:01:06.683 回答