1. ホーム
  2. c#

[解決済み】ASP.NET MVCでファイルを表示/ダウンロードに戻す場合

2022-03-26 21:20:53

質問

ASP.NET MVCで、データベースに保存されたファイルをユーザーに送り返す問題に遭遇しています。1つはファイルを表示し、ブラウザに送信されるmimetypeがそれをどのように処理するかを決定するようにするもので、もう1つは強制的にダウンロードするものです。

というファイルを表示するように選択した場合 SomeRandomFile.bak ブラウザにこの種のファイルを開くための関連プログラムがない場合、ダウンロードの動作がデフォルトになるのは問題ありません。しかし、もし私が SomeRandomFile.pdf または SomeRandomFile.jpg 単純にファイルを開きたい。しかし、ファイルの種類に関係なくダウンロードのプロンプトを強制的に表示できるように、ダウンロードのリンクを横に置いておきたいのです。これは意味があるのでしょうか?

試してみたのは FileStreamResult そのため、未知のファイルには URL に基づいてファイル名が割り当てられます (URLはコンテンツ タイプに基づいて与えるべき拡張子を知りません)。ファイル名を強制的に指定すると、ブラウザが直接ファイルを開く機能を失い、ダウンロードのプロンプトが表示されます。他にこのような現象に遭遇した方はいらっしゃいますか?

今まで試した例です。

//Gives me a download prompt.
return File(document.Data, document.ContentType, document.Name);

//Opens if it is a known extension type, downloads otherwise (download has bogus name and missing extension)
return new FileStreamResult(new MemoryStream(document.Data), document.ContentType);

//Gives me a download prompt (lose the ability to open by default if known type)
return new FileStreamResult(new MemoryStream(document.Data), document.ContentType) {FileDownloadName = document.Name};

何かご意見はありますか?


UPDATEです。 この質問は多くの人の心を打つようなので、私は更新を投稿しようと思いました。Oskar によって追加された、以下の受理された回答での国際文字に関する警告は完全に有効です。 ContentDisposition クラスがあります。その後、これを修正するために私の実装を更新しました。以下のコードは、ASP.NET Core (Full Framework) アプリでこの問題を解決した最新のものですが、古い MVC アプリケーションでも最小限の変更で動作するはずです。 System.Net.Http.Headers.ContentDispositionHeaderValue クラスがあります。

using System.Net.Http.Headers;

public IActionResult Download()
{
    Document document = ... //Obtain document from database context

    //"attachment" means always prompt the user to download
    //"inline" means let the browser try and handle it
    var cd = new ContentDispositionHeaderValue("attachment")
    {
        FileNameStar = document.FileName
    };
    Response.Headers.Add(HeaderNames.ContentDisposition, cd.ToString());

    return File(document.Data, document.ContentType);
}

// an entity class for the document in my database 
public class Document
{
    public string FileName { get; set; }
    public string ContentType { get; set; }
    public byte[] Data { get; set; }
    //Other properties left out for brevity
}

解決方法は?

public ActionResult Download()
{
    var document = ...
    var cd = new System.Net.Mime.ContentDisposition
    {
        // for example foo.bak
        FileName = document.FileName, 

        // always prompt the user for downloading, set to true if you want 
        // the browser to try to show the file inline
        Inline = false, 
    };
    Response.AppendHeader("Content-Disposition", cd.ToString());
    return File(document.Data, document.ContentType);
}

NOTE 上記のコード例では、ファイル名の国際文字が適切に考慮されていません。関連する標準化については、RFC6266を参照してください。私は、最近のバージョンのASP.Net MVCの File() メソッドと ContentDispositionHeaderValue クラスはこれを適切に考慮します。- オスカル 2016-02-25