【问题标题】:displaying htm contents in browser via Response.Writefile in ASP.Net通过 ASP.Net 中的 Response.Writefile 在浏览器中显示 htm 内容
【发布时间】:2012-04-18 20:18:14
【问题描述】:

我正在开发一个我继承的网站,该网站是用 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

这是页面中的一个 sn-p 代码:

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 对象或其他东西做些什么吗?我不能让它打开一个显示文件的新浏览器窗口,还是如果以这种方式使用它必须提示用户??

【问题讨论】:

    标签: asp.net vb.net


    【解决方案1】:

    放弃整页 (.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 上,您需要从 <system.web> 中删除任何 <httpHandler> 注册,并将它们注册为 <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 主机开发,那么我建议为您的网络使用(并在必要时安装)IIS Express 选项项目。这可以在您的 Web 项目的“属性”中找到,从左侧开始的“Web”选项卡,然后在“服务器”部分中,选择“使用本地 IIS Web 服务器”单选按钮,然后选中下方的“使用 IIS Express”。

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

    【讨论】:

    • 对不起,终于开始实现这个了,它就像一个魅力 - 我使用了来自 dotnetperls.com/ashx 的代码,以便将正确的文件名输入到处理程序中。
    • 然而,我唯一的问题是,即使我正在实现 IRequiresSessionState,如您在上面显示的那样,我也可以在不登录的情况下访问 url,从而访问文件......知道为什么可能是?
    • 没关系,我想我只需要编写条件代码,如果未设置会话变量,用户将无法访问该页面。
    • 所以这在我的本地 VS 实例和临时 Web 服务器上运行良好,但是当将它传输到我们的服务器并让他们更新 dll 时,它似乎在那里不起作用。最初它给出了解析错误(无法创建类型 X,其中 X 是我给我的处理程序的类名)。然后管理员做了一些更新后,它开始工作,但只提示保存而不是打开文档文件。这一切都没有发生在我的本地实例上。他们的 web.config 设置是否与此相关?
    • @LeviWallach 主机上的 IIS 是什么版本?我也不必在本地添加任何内容,但我似乎记得有一个用于 IIS 6 的 web.config 条目。对此进行调查,并将根据我的发现更新答案。
    【解决方案2】:

    经过一番讨论,看来您可能最好使用 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 主机上的一些日志条目尝试“访问已关闭的流”,但页面将继续照常处理。这是从本质上劫持正常页面流所要付出的代价之一。

    【讨论】:

    • 我得到了这个工作,以便它将 html 内联文件与其他文件作为附件提供。但是,我之前遇到的行为(会话粘性),我今天没有看到。希望我不只是想象它!目前看来不可能,但如果有一些解决方法,我很想知道!
    【解决方案3】:

    当您调用Response.WriteFile() 时,服务器可能会丢弃您手动设置的内容类型标头。当客户端收到它时,找出实际的内容类型标头是什么。 Firebug 会告诉你如果你在它的网络标签下查看。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-01-25
      • 2011-01-31
      • 2015-09-15
      • 2020-11-10
      • 2022-10-20
      • 1970-01-01
      • 2011-02-19
      相关资源
      最近更新 更多