1

私は、ASP.Net で構築された、継承したサイトで作業していますが、これには少し慣れています。ページの 1 つは、ドキュメント (word または pdf) へのリンクを許可し、クリックすると、ユーザーにファイルを保存するか開くように促しますが、ファイルの実際のパスは明らかにしません。このようにして、ユーザーが URL をファイルに貼り付けるのを防ぎます。リンクは、有効なセッションをチェックしてからファイルを取得する aspx ファイルへのリンクです。

とにかく、多くのレガシー コードがあるため、静的な htm ファイルの束でもこれを行う必要がありますが、これらのファイルは、ユーザーに保存するように求めるのではなく、表示する必要があります。コンテンツ タイプを application/text、application/html、text/html などに変更しようとしましたが、うまくいかず、content-disposition インラインの応答ヘッダーを追加してみました。それを行ってビルドし、ファイルにリンクしようとすると、いくつかの実行時例外が発生します。

[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

汎用ハンドラー (.ashx) を使用する代わりに、ページ全体 (.aspx) のアプローチを廃止します。.aspx ページは、ASP.NET Web ページで通常使用されるすべての状態を初期化するために多くの組み込みの読み込みを実行しますが、汎用ハンドラーは出力をクライアントに送り返すために最小限の初期化のみを行います。 .

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

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 ホストに発生する可能性があることに注意してください。ただし、ページは通常どおり処理を続行します。これは、通常のページ フローを本質的にハイジャックする代償の 1 つです。

于 2012-05-09T19:01:06.683 に答える
0

を呼び出すと、サーバーが手動で設定した content-type ヘッダーを破棄している可能性がありますResponse.WriteFile()。クライアントが受信したときに、実際の content-type ヘッダーが何であるかを調べます。 Firebugは、Net タブの下を見ると教えてくれます。

その場合は、Response.ContentTypeを呼び出してから設定してみてくださいResponse.WriteFile()。または、ファイルを文字列に読み込んで、のResponse.Write()代わりに使用することもできますWriteFile

于 2012-04-18T20:37:52.773 に答える