web-dev-qa-db-ja.com

ASP.NET MVCでファイルを表示/ダウンロードに戻る

データベースに保存されているファイルをASP.NET MVCのユーザーに送信する際に問題が発生しました。私が欲しいのは二つのリンクをリストアップしたビューです。一つはファイルを見てブラウザに送られたMIMEタイプに処理方法を決定させ、もう一つはダウンロードを強制するものです。

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

私はFileStreamResultを試してみました、そしてそれはほとんどのファイルのために働きます、それはコンストラクタがデフォルトでファイル名を受け入れないので、未知のファイルは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};

助言がありますか?


アップデート:この質問は多くの人と和解するようなので、アップデートを投稿することにしました。国際的な文字に関してOskarによって追加された以下の受け入れられた答えに対する警告は完全に有効です、そして私はContentDispositionクラスを使用することでそれを数回ヒットしました。私はその後これを修正するために私の実装を更新しました。以下のコードは、ASP.NET Core(Full Framework)アプリケーションでの私の最新のこの問題の実体からのものですが、私はSystem.Net.Http.Headers.ContentDispositionHeaderValueクラスを使用しているので、古いMVCアプリケーションでも最小限の変更で動作するはずです。

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
}
271
Nick Albrecht
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);
}

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

405
Darin Dimitrov

Darin Dimitrovの答え は正しいです。ちょっと追加:

応答に既に "Content-Disposition"ヘッダーが含まれている場合、Response.AppendHeader("Content-Disposition", cd.ToString());を使用するとブラウザでファイルのレンダリングが失敗する可能性があります。その場合は、次のようにします。

Response.Headers.Add("Content-Disposition", cd.ToString());
12
Leo

ファイルを見る(例えばtxt):

return File("~/TextFileInRootDir.txt", MediaTypeNames.Text.Plain);

ファイルにダウンロードする(たとえばtxt):

return File("~/TextFileInRootDir.txt", MediaTypeNames.Text.Plain, "TextFile.txt");

注:ファイルをダウンロードするには、fileDownloadName引数を渡す必要があります

9
Ashot Muradian

私はこの答えがきれいだと思います( https://stackoverflow.com/a/3007668/550975 に基づく)。

    public ActionResult GetAttachment(long id)
    {
        FileAttachment attachment;
        using (var db = new TheContext())
        {
            attachment = db.FileAttachments.FirstOrDefault(x => x.Id == id);
        }

        return File(attachment.FileData, "application/force-download", Path.GetFileName(attachment.FileName));
    }
3
Serj Sagan

FileVirtualPath - > Research\Global Office Review.pdf

public virtual ActionResult GetFile()
{
    return File(FileVirtualPath, "application/force-download", Path.GetFileName(FileVirtualPath));
}
1
Bishoy Hanna

以下のコードは、APIサービスからpdfファイルを取得し、それをブラウザに応答させるために役立ちました。

public async Task<FileResult> PrintPdfStatements(string fileName)
    {
         var fileContent = await GetFileStreamAsync(fileName);
         var fileContentBytes = ((MemoryStream)fileContent).ToArray();
         return File(fileContentBytes, System.Net.Mime.MediaTypeNames.Application.Pdf);
    }
0
Jonny Boy