none
asp.netでテキストファイルをダウンロードすると、テキストに変な文字がくっついてきます。 RRS feed

  • 質問

  • マイクロソフトコミュニティから移動してきました。よろしくお願いします。

    asp.net 2010 (Professional)、IE9でダウンロードページを作成しています。
    サーバサイド処理に、ファイルダウンロードのコードを書いています。

    ファイルはダウンロードできたのですが、ダウンロードしたテキストファイル(拡張子が.txtや.log)
    をメモ帳で開くと、ファイルの末尾に、元のファイルにはない文字が書かれてしまいます。
    テキストファイルの末尾に書かれている文字は、ダウンロード画面のマークアップ(DownloadPage.aspx)の内容です。
     
    ■DownloadPage.aspx.vb

    Dim strTempPath As String = "C:\Temp\aaaaa.txt"
    Dim strDownloadFileName As String = "bbbbb.txt"

    With Response
         .ContentType = "application/octet-stream"
         .HeaderEncoding = System.Text.Encoding.GetEncoding("Shift_JIS")
         .AppendHeader("Content-Disposition", "attachment;filename=" + Server.UrlEncode(strDownloadFileName))
         .WriteFile(strTempPath)
         .Flush()
         .End()
    End With

    ■ダウンロードしたテキストファイルに余分に書かれている文字

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ttp://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd>

    <html xmlns=ttp://www.w3.org/1999/xhtml >
    <head><title>
     ダウンロード画面
    </title><link id="incCssCommon" href="../test.css" rel="stylesheet" type="text/css" />

    <script type="text/javascript" src="../jquery-1.5.1.min.js"></script>
    <script type="text/javascript">

    ・・・ 以下省略 ・・・

    なぜこんなことになるのかわかりません。 どうしたら、末尾の文字なしのファイルがダウンロードできますか。
    ちなみに、 同じ処理を拡張子=PDFのファイルを使った場合には問題は起こりません。

    2013年4月4日 8:07

回答

すべての返信

  • 以下のスレッドに書いてあることと同じ原因ではないですか?

    HttpResponse.WriteとかWriteFileするとデフォルトで付いてしまう<!DOCTYPE html PUBLIC "-//W3C//DTD ・・・>タグを消すには?
    http://social.msdn.microsoft.com/Forums/ja-JP/aspnetja/thread/b7b5e136-e8bd-457b-8993-aaa9893902ae


    アップされたコードには End メソッドがありますが、<!DOCTYPE ... がくっついてくるということですと、理由不明ですが End では終わってなくて、Page の html コードをすべて送信してから終了しているとしか考えられません。

    • 回答の候補に設定 星 睦美 2013年4月8日 4:35
    • 回答としてマーク 星 睦美 2013年4月11日 1:37
    2013年4月4日 8:53
  • SurferOnWwwさんありがとうございます。

    教えていただいたページの現象と同じです。

    それで、そのページのさらにリンク

    ttp://surferonwww.info/BlogEngine/post/2013/02/16/use-http-handler-for-downloading-files.aspx

    に書いてあったとおりに、ashxファイルを作ってみたのですが、やはり同じ結果になりました。

    ashxの呼び出し方、間違っていますか。

    ■Handler1.ashx.vb

    Imports System.Web
    Imports System.Web.Services

    Public Class Handler1
        Implements System.Web.IHttpHandler

        Private _downloadFilePath As String = ""
        Private _downloadFileName As String = ""

        Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest

            Dim response As HttpResponse = context.Response
            Dim request As HttpRequest = context.Request

            If (request.Browser.Browser.ToUpper().IndexOf("IE") >= 0) Then
                _downloadFileName = context.Server.UrlEncode(_downloadFileName)
            End If

            response.AppendHeader("Content-Disposition", "attachment;filename=" + _downloadFileName)
            response.ContentType = "text/plain"
            response.TransmitFile(_downloadFilePath)
            'response.Write("Hello World")

        End Sub

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

        Public Sub New(ByVal strTempPath As String, ByVal strDownloadFileName As String)
            _downloadFilePath = strTempPath
            _downloadFileName = strDownloadFileName
        End Sub
    End Class

    ■ダウンロードページからの呼び出し

    Dim cls As New Handler1(strTempPath, strDownloadFileName)
    cls.ProcessRequest(Me.Context)

    よろしくお願いします。

    2013年4月5日 3:57
  • 少し直してみたら動くようになりました。

    ashxも、aspxと同じように呼び出せばよかったのですね。

    引数はQueryStringで渡すようにしました。

     ・ashx.vbのNewを削除

     ・ProcessRequestの中で、QueryStringを取得

     ・呼出側はResponse.Redirectでashxを呼び出す

    ■Handler1.ashx.vb

    Imports System.Web
    Imports System.Web.Services

    Public Class Handler1
        Implements System.Web.IHttpHandler

        Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest

            Dim response As HttpResponse = context.Response
            Dim request As HttpRequest = context.Request

            Dim strFilePath As String = request.QueryString("path")
            Dim strDownloadFileName As String = request.QueryString("filename")

            If (request.Browser.Browser.ToUpper().IndexOf("IE") >= 0) Then
                strDownloadFileName = context.Server.UrlEncode(strDownloadFileName)
            End If

            response.AppendHeader("Content-Disposition", "attachment;filename=" + strDownloadFileName)
            response.ContentType = "text/plain"
            response.TransmitFile(strFilePath)  ' 指定したファイル
            'response.Write("Hello World")      ' 文字列を出力する場合はこちら

        End Sub

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

    End Class

    ■呼出側

    Response.Redirect("~/・・・/Handler1.ashx?path=" & strTempPath &  _

     "&filename=" & strDownloadFileName)

    ashxファイル、初めて使いました。勉強になりました。

    SurferOnWwwさん、本当にありがとうございました。

    2013年4月5日 4:35
  • > ashxも、aspxと同じように呼び出せばよかったのですね。
    >
    > 引数はQueryStringで渡すようにしました。

    そうです、それでいいと思います。


    > ・呼出側はResponse.Redirectでashxを呼び出す

    HttpResponse.Redirect メソッド (String) は非推奨の End メソッドを呼び出しますので注意してください(ThreadAbortException 例外をスローするので、アプリケーションのパフォーマンスに悪影響があります)。

    HttpResponse.Redirect メソッド (String)
    http://msdn.microsoft.com/ja-jp/library/vstudio/t9dwyts4.aspx

    上のページに書いてあるように、HttpResponse.Redirect(String, Boolean) オーバーロードを使用するのがお勧めだそうです。

    2013年4月5日 5:18
  • SurferOnWwwさん、追加のアドバイスありがとうございます。

    Redirectメソッド、説明書きを読みました。Webアプリのパフォーマンスに関係してくるところのようですね。

    パフォーマンスがどの程度落ちて、どの程度困るのかよくわかりませんが、推奨の記述に変えておきます。

    ※普段はWinアプリばかり作っているので、Web系特有の仕組みや概念が今一つピンと来ず・・・。要勉強ですね。

    2013年4月8日 4:30
  • 気をつけているであろうとは思いますが念のため。

    今のコードだと、クライアントから指定した任意のファイル(実行アカウントに読み取り権限は必要ですが)をダウンロードできてしまうような気がしますので、注意してくださいね。

    2013年4月8日 6:02
  • なちゃ様

    ご指摘ありがとうございます。

    URLを手で打ち込んでみたら、おっしゃるとおり何でもダウンロードできてしまいました。

    セッション管理のコード、追加してみます。

    2013年4月9日 3:47
  • フォーラム オペレーターの星 睦美です。

    SurferONWww さん、なちゃ さん アドバイスありがとうございます。

    saZQ さん、こんにちは
    私のほうで今回の質問の解決に役立った情報としてSurferONWww さんの返信に[回答の候補に設定] させていただきました。
    コミュニティで良い回答を共有するために、投稿者から参考になった返信に[回答としてマーク]をお願いします。

    なちゃ さんからのアドバイスにさらに質問がありましたら、質問と回答が分かりやすいスレッドになるように新しいスレッドを作成していただければと思います。

    それではこれからもMSDN フォーラムをお役立てください。


    日本マイクロソフト株式会社 フォーラム オペレーター 星 睦美

    2013年4月9日 4:23
  • > セッション管理のコード、追加してみます。

    「セッション管理」とはどういう意味かわかりませんが、何にせよ、ワーカープロセスのアクセス権の設定で対応可能だと思いますが。

    2013年4月9日 16:26
  • > セッション管理のコード、追加してみます。

    「セッション管理」とはどういう意味かわかりませんが、何にせよ、ワーカープロセスのアクセス権の設定で対応可能だと思いますが。

    だめですよ。
    それでは、例えばWeb.configとかをダウンロードできたり等々してしまいます。
    ちょっと単純に権限設定とかではできません。

    ではどうするかということなのですが、そもそもこのダウンロードのプログラムがどういう目的のものか、どういうファイルをダウンロードするものかなどに依存してきますので、単純にひとつの解があるというような話でもありません。

    例えば特定のダウンロード用フォルダを決めて、そこ以外を完全にはじく(これもチェックはそれなりに注意が必要)ようにするというようなやり方もあるでしょうし、あるいはファイル名指定ではなくID指定で対応するファイルのみダウンロードできるように制御する(考え方的には可能ならこちらの方がお勧め)など方法はいろいろ考えられますが、どういう方法がよいかというと、どういうダウンロード機能なのかによっても変わってきます。

    -----追記

    あ、もしかすると、偽装して権限設定で、とか言われるかもしれませんが、それも含めて権限設定で制御するのはお勧めできません。

    -----さらに追記

    何度もすみません、一時的にだけ偽装してというのならありかもしれません(お勧めかというとやや微妙ですが)。
    ただ、偽装した状態でTransmitFileとかが普通に使えるのかは試してないのでちょっとわかりません。

    • 編集済み なちゃ 2013年4月10日 1:32
    2013年4月10日 0:35
  • > だめですよ。

    断定的ですね。ダメかどうかは質問者さんが判断することだと思います。

    > 単純にひとつの解があるというような話でもありません。

    というのはその通りだと思います。なので、ワーカープロセスのアクセス権の設定で対応するのも、質問者さんの環境では解になるかもしれません。

    質問者さんの最初の質問に、

    > Dim strTempPath As String = "C:\Temp\aaaaa.txt"

    とありましたので、アプリケーションルートではない特定のフォルダにダウンロードするファイルがあるようです。その状態で、

    > URLを手で打ち込んでみたら、おっしゃるとおり何でもダウンロード
    > できてしまいました。

    とのことですので、ワーカープロセスのアクセス権の設定に問題があって、本来アクセスを許すべきでないフォルダまでアクセスできてしまう状況ではないでしょうか?

    であれば、ワーカープロセスに、適切に、C:\Temp フォルダに対するアクセス権のみ与えておけば、問題は解決するかもしれません。そのあたりは質問者さんに聞かないと分かりませんが。

    2013年4月10日 8:59
  • > だめですよ。

    断定的ですね。ダメかどうかは質問者さんが判断することだと思います。

    いやダメでしょう。

    いくらなんでも常識的な範囲というものがあるでしょう。

    少なくとも、真っ先に挙げる方法としてこれというのはありえないでしょう。

    そんなことはないとおっしゃるならそれはもう見解の相違としか。

    であれば、ワーカープロセスに、適切に、C:\Temp フォルダに対するアクセス権のみ与えておけば、問題は解決するかもしれません。そのあたりは質問者さんに聞かないと分かりませんが。

    そんな状態でASP.NETは実行できるのですか?

    2013年4月10日 13:36
  • > いやダメでしょう。
    > いくらなんでも常識的な範囲というものがあるでしょう。

    一般的に「常識的な範囲」というのは普遍ではなくて、環境・要件によって変わってくるはずです。

    質問者さんの環境・要件を知らない第三者と、質問者さんが共有できないかもしれない第三者の「常識」をベースに議論しても意味がなさそうですので、質問者さんから「自分の環境はこうだから、こういう理由で、ワーカープロセスのアクセス権の設定だけでは解決しない」というようなダメ出しがあったら、その時点でまた解決策を議論したいと思います。


    > そんな状態でASP.NETは実行できるのですか?

    そのあたりも「常識的な範囲」の違いによる誤解なのかもしれません。

    先の私のレスを、ワーカープロセスには、アプリケーションルートにアクセス権を与えず、C:\Temp フォルダにのみ与えると解釈しましたか?

    自分としてはそんなこと(アプリケーションルートにアクセス権を与えない)は考えてもいませんでしたが、そういう解釈をされる方がいたとしたら、自分の「常識的な範囲」を超えていたようで、先の私のレスは言葉足らずだったようです。

    2013年4月11日 2:14
  • > いやダメでしょう。
    > いくらなんでも常識的な範囲というものがあるでしょう。

    一般的に「常識的な範囲」というのは普遍ではなくて、環境・要件によって変わってくるはずです。

    質問者さんの環境・要件を知らない第三者と、質問者さんが共有できないかもしれない第三者の「常識」をベースに議論しても意味がなさそうですので、質問者さんから「自分の環境はこうだから、こういう理由で、ワーカープロセスのアクセス権の設定だけでは解決しない」というようなダメ出しがあったら、その時点でまた解決策を議論したいと思います。

    99%常識でやるべきでないようなことを言い張って何か意義があるんですかね?

    ----追記ここから

    99%とか書きましたが、これは単にほとんど程度の意味ですが、これでは言いたいことを正確に表現できていないのでちょっと訂正します。

    環境によって問題が発生しないことはあり得るかもしれませんが、たとえ実害がなくともやってはいけないことであるのは常識です。
    まるで私が勝手に常識と言ってるだけに見えているのかもしれませんが、例えばSQLインジェクションはダメというのと同様の意味でだめです。
    SQLインジェクションの脆弱性があっても実害のない環境はあり得るかもしれませんが、それでもやってはいけないことであるのは常識です。

    質問者の環境ではSQLインジェクションがあっても実害はないかもしれないので、第三者が言っても意味がないとか言うんでしょうか?
    今回のは、例えて言うならあなたが、SQLインジェクションの脆弱性があるようなやり方を示した、というような状況ですよ。

    ----追記ここまで

    しかも最初にあなたは何と言って提案しましたか?これでできると思いますけどくらいの軽い提案でしたね?
    一体どれほどのリスクを抱える提案か、一言でも補足なり注意をしましたか?

    最初は問題点を失念しただけかと思いましたが、あくまで本気の提案で特に補足する気もなかったということでしたか。

    > そんな状態でASP.NETは実行できるのですか?

    そのあたりも「常識的な範囲」の違いによる誤解なのかもしれません。

    先の私のレスを、ワーカープロセスには、アプリケーションルートにアクセス権を与えず、C:\Temp フォルダにのみ与えると解釈しましたか?

    自分としてはそんなこと(アプリケーションルートにアクセス権を与えない)は考えてもいませんでしたが、そういう解釈をされる方がいたとしたら、自分の「常識的な範囲」を超えていたようで、先の私のレスは言葉足らずだったようです。

    であればなおさら、危険も、アプリケーション内のあらゆるファイルをクライアントからダウンロード可能のままであることも、何もかもわかったうえでこれでできるのでは?と提案したのですね。

    ところでASP.NETはアプリケーションのルート以外に読み取り権限は不要で動作するんでしょうか?
    詳細は私も分かりませんが、それでは動くはずがないと思います。

    もしTempにだけ読み取り権限を与えればよいというのであれば、ASP.NETが問題なく実行できて、その上でTemp以外の不要なフォルダの読み取り権限を完全に外す方法くらいは提示してほしいです。私も知りたい。

    で、そのうえで、どのくらいのファイルがクライアントからダウンロードできるのか、質問者が問題ないか判断できるように情報を提示してください。
    今のままではそもそも質問者に判断できるような情報がありません。

    • 編集済み なちゃ 2013年4月11日 15:36
    2013年4月11日 13:21
  • あと、これはもうつまるところ見解の相違なのでしょうけれど、Webアプリケーションにおいて、Webアプリケーションのルート配下のあらゆるファイルをクライアントからダウンロードできるような状態は、避けるかべきかどうかは人それぞれだとか、そんなあえてやったりするようなことなんでしょうか?

    ASPXファイルやソースファイルも(プリコンパイル等々でない環境はあるにしても)、設定ファイルも、dllも、アプリが何等かアクセスするファイルも、標準のDBファイルを使っていればそのファイルも、何もかもクライアントからダウンロードできるのですよ?

    アプリケーションに何かファイル関係を追加するたびに、このファイルがダウンロード可能で問題ないか確認して、もし問題あればその時点で破綻するのですよ?

    その上、マシン内の他のファイルも、これはどこまでか把握もできませんが、あちこちにダウンロード可能なファイルが存在することになるでしょう。
    もしファイル共有なんか利用したらどうなるか。

    こんなの、常識で最初から止めとくしか、私には考えられません。

    2013年4月11日 13:34