65

特定の名前でブラウザー内でASP.NETMVCFileContentResultを使用してファイルをストリーミングする方法はありますか?

FileDialog(開く/保存)を使用するか、ブラウザウィンドウでファイルをストリーミングすることができますが、ファイルを保存しようとするとActionNameが使用されることに気付きました。

次のシナリオがあります。

byte[] contents = DocumentServiceInstance.CreateDocument(orderId, EPrintTypes.Quote);
result = File(contents, "application/pdf", String.Format("Quote{0}.pdf", orderId));

これを使用すると、バイトをストリーミングできますが、OPEN/SAVEファイルダイアログがユーザーに表示されます。このファイルを実際にブラウザウィンドウでストリーミングしたいと思います。

FilePathResultを使用すると、ブラウザウィンドウにファイルが表示されますが、[保存]ボタンをクリックしてファイルをPDFで保存すると、ファイルの名前としてアクション名が表示されます。

誰かがこれに遭遇しましたか?

4

7 に答える 7

96
public ActionResult Index()
{
    byte[] contents = FetchPdfBytes();
    return File(contents, "application/pdf", "test.pdf");
}

Content-Dispositionブラウザ内でPDFを開くには、ヘッダーを設定する必要があります。

public ActionResult Index()
{
    byte[] contents = FetchPdfBytes();
    Response.AddHeader("Content-Disposition", "inline; filename=test.pdf");
    return File(contents, "application/pdf");
}
于 2010-07-08T19:37:17.513 に答える
60

実際、絶対に簡単な方法は次のことを行うことです...

byte[] content = your_byte[];

FileContentResult result = new FileContentResult(content, "application/octet-stream") 
{
  FileDownloadName = "your_file_name"
};

return result;
于 2013-04-15T10:34:44.163 に答える
13

これは、他の誰もがこの問題に直面している場合に役立つ可能性があります。私はついに解決策を見つけました。「content-disposition」にインラインを使用してファイル名を指定しても、ブラウザはファイル名を使用しないことがわかりました。代わりに、ブラウザはパス/URLに基​​づいてファイル名を解釈しようとします。

あなたはこのURLでさらに読むことができます: 正しいファイル名でブラウザ内のファイルを安全にダウンロードしてください

これは私にアイデアを与えました、私はちょうどURLを変換し、ファイルに与えたいファイルの名前でそれを終わらせる私のURLルートを作成しました。たとえば、私の元のコントローラー呼び出しは、印刷されている注文の注文IDを渡すことだけで構成されていました。ファイル名はOrder{0}.pdfの形式であると予想していました。ここで、{0}は注文IDです。同様に、見積もりについては、Quote{0}.pdfが必要でした。

私のコントローラーでは、先に進んで、ファイル名を受け入れるためのパラメーターを追加しました。URL.Actionメソッドのパラメーターとしてファイル名を渡しました。

次に、そのURLを次の形式にマップする新しいルートを作成しました: http://localhost/ShoppingCart/PrintQuote/1054/Quote1054.pdf


routes.MapRoute("", "{controller}/{action}/{orderId}/{fileName}",
                new { controller = "ShoppingCart", action = "PrintQuote" }
                , new string[] { "x.x.x.Controllers" }
            );

これで私の問題はほぼ解決しました。これが誰かを助けることを願っています!

Cheerz、Anup

于 2010-07-15T05:16:47.530 に答える
8

以前の答えは正しいです:行を追加します...

Response.AddHeader("Content-Disposition", "inline; filename=[filename]");

...複数のContent-Dispositionヘッダーがブラウザに送信されます。これは、ファイル名を指定した場合、b/cFileContentResultがヘッダーを内部的に適用する場合に発生します。別の非常に単純な解決策は、のサブクラスを作成し、そのメソッドFileContentResultをオーバーライドすることです。クラスのインスタンス(内部実装で使用されているのと同じオブジェクト)をインスタンス化し、それを新しいクラスに渡すExecuteResult()例を次に示します。System.Net.Mime.ContentDispositionFileContentResult

public class FileContentResultWithContentDisposition : FileContentResult
{
    private const string ContentDispositionHeaderName = "Content-Disposition";

    public FileContentResultWithContentDisposition(byte[] fileContents, string contentType, ContentDisposition contentDisposition)
        : base(fileContents, contentType)
    {
        // check for null or invalid ctor arguments
        ContentDisposition = contentDisposition;
    }

    public ContentDisposition ContentDisposition { get; private set; }

    public override void ExecuteResult(ControllerContext context)
    {
        // check for null or invalid method argument
        ContentDisposition.FileName = ContentDisposition.FileName ?? FileDownloadName;
        var response = context.HttpContext.Response;
        response.ContentType = ContentType;
        response.AddHeader(ContentDispositionHeaderName, ContentDisposition.ToString());
        WriteFile(response);
    }
}

ControllerまたはベースControllerで、をインスタンス化する簡単なヘルパーを記述し、 FileContentResultWithContentDisposition次のようにアクションメソッドから呼び出すことができます。

protected virtual FileContentResult File(byte[] fileContents, string contentType, ContentDisposition contentDisposition)
{
    var result = new FileContentResultWithContentDisposition(fileContents, contentType, contentDisposition);
    return result;
}

public ActionResult Report()
{
    // get a reference to your document or file
    // in this example the report exposes properties for
    // the byte[] data and content-type of the document
    var report = ...
    return File(report.Data, report.ContentType, new ContentDisposition {
        Inline = true,
        FileName = report.FileName
    });
}

これで、ファイルは、選択したファイル名と「inline; filename=[filename]」のcontent-dispositionヘッダーでブラウザに送信されます。

お役に立てば幸いです。

于 2013-07-26T23:07:00.550 に答える
6

ASP.NETMVCを使用してファイルをブラウザーにストリーミングする最も簡単な方法は次のとおりです。

public ActionResult DownloadFile() {
    return File(@"c:\path\to\somefile.pdf", "application/pdf", "Your Filename.pdf");
}

これは、バイトを読み取る必要さえないため、@azarc3によって提案された方法よりも簡単です。

クレジットは次の場所に移動します:http://prideparrot.com/blog/archive/2012/8/uploading_and_returning_files#how_to_return_a_file_as_response

** 編集 **

どうやら私の「答え」はOPの質問と同じです。しかし、私は彼が抱えている問題に直面していません。おそらく、これは古いバージョンのASP.NET MVCの問題でしたか?

于 2015-04-01T14:05:25.753 に答える
0

私はそれをRESTAPIを使用してASP.NETCoreに適合させました。

public class FileContentWithFileNameResult : FileContentResult
{
    public FileContentWithFileNameResult(byte[] fileContents, string contentType, string fileName)
   : base(fileContents, contentType)
    {
        FileName = fileName;
    }

    public string FileName { get; private set; }

    public override Task ExecuteResultAsync(ActionContext context)
    {
        var response = context.HttpContext.Response;  
        response.Headers.Append("Content-Disposition", $"inline; filename={FileName}");
        response.Headers.Append("Access-Control-Expose-Headers", "Content-Disposition");
        response.Headers.Append("X-Content-Type-Options", "nosniff");
        return base.ExecuteResultAsync(context);
    }
}
于 2021-10-04T16:19:18.130 に答える
-1
public FileContentResult GetImage(int productId) { 
     Product prod = repository.Products.FirstOrDefault(p => p.ProductID == productId); 
     if (prod != null) { 
         return File(prod.ImageData, prod.ImageMimeType); 
      } else { 
         return null; 
     } 
}
于 2013-07-26T11:42:58.783 に答える