Web APIを使用してファイルを返す方法は?


98

ASP.NET Web APIを使用しています
API(APIが生成する)からC#でPDFをダウンロードしたい。

APIにを返すだけでbyte[]いいですか?そしてC#アプリケーションのために私はただ行うことができます:

byte[] pdf = client.DownloadData("urlToAPI");? 

そして

File.WriteAllBytes()?

「Web API」?どういう意味ですか?tinyurl.com/so-hintsを読んで、質問を編集してください。
Jon Skeet

1
@JonSkeet:Web APIは、ASP.NETの最新バージョンの新機能です。asp.net/whitepapers/mvc4-release-notes#_Toc317096197を
Robert Harvey

1
@ロバート:ありがとう-「ASP.NET Web API」への言及はさらに明確でしたが、タグはそれをより明確にします。部分的には、MSのごく一般的な名前の誤りも:)
Jon Skeet


:ここを参照し、Web APIとIHTTPActionResult経由でストリームを返したい土地誰でもnodogmablog.bryanhogan.net/2017/02/...
IbrarMumtaz

回答:


170

StreamContentを内部に含むHttpResponseMessageを返す方が適切です。

次に例を示します。

public HttpResponseMessage GetFile(string id)
{
    if (String.IsNullOrEmpty(id))
        return Request.CreateResponse(HttpStatusCode.BadRequest);

    string fileName;
    string localFilePath;
    int fileSize;

    localFilePath = getFileFromID(id, out fileName, out fileSize);

    HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
    response.Content = new StreamContent(new FileStream(localFilePath, FileMode.Open, FileAccess.Read));
    response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
    response.Content.Headers.ContentDisposition.FileName = fileName;
    response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");

    return response;
}

パトリッジによるコメントからのUPD:他の誰かが実際のファイルではなくバイト配列から応答を送信するためにここに来た場合、StreamContentではなく新しいByteArrayContent(someData)を使用することになります(ここを参照)。


1
まず最初に-同じファイルを指す2つのFileStreamオブジェクトを新しく作成するため、このコードは例外を発生させます。2つ目は、「Using」ステートメントを使用しないことです。これは、変数がスコープから外れるとすぐに.NETがそれを破棄し、基になる接続が閉じられているというエラーメッセージが表示されるためです。
ブランドンモンゴメリー

48
他の誰かが実際のファイルの代わりにバイト配列から応答を送信するためにここに来た場合、new ByteArrayContent(someData)代わりに使用したいでしょうStreamContentここを参照)。
パトリッジ2013年

フレームワークがリソースを呼び出すときにリソースを正しく処理できるように、ベースのdispose()をオーバーライドすることもできます。
Phil Cooper

1
私は正しいMediaTypeHeaderValueが重要であり、このようにできる異なるファイルタイプがある場合は動的にするために重要であることを指摘したいと思います。(fileNameは文字列で、.jpg、.pdf、docxなどのようなファイルタイプで終わります。)var contentType = MimeMapping.GetMimeMapping(fileName); response.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
JimiSweden 2016

1
FileStreamは自動的に破棄されますか?
ブライアンタッカー

37

私は次のアクションを行いました:

[HttpGet]
[Route("api/DownloadPdfFile/{id}")]
public HttpResponseMessage DownloadPdfFile(long id)
{
    HttpResponseMessage result = null;
    try
    {
        SQL.File file = db.Files.Where(b => b.ID == id).SingleOrDefault();

        if (file == null)
        {
            result = Request.CreateResponse(HttpStatusCode.Gone);
        }
        else
        {
            // sendo file to client
            byte[] bytes = Convert.FromBase64String(file.pdfBase64);


            result = Request.CreateResponse(HttpStatusCode.OK);
            result.Content = new ByteArrayContent(bytes);
            result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
            result.Content.Headers.ContentDisposition.FileName = file.name + ".pdf";
        }

        return result;
    }
    catch (Exception ex)
    {
        return Request.CreateResponse(HttpStatusCode.Gone);
    }
}

これは実際に質問に答えます
Mick

1
画像全体をメモリにロードするため、大きなファイルの場合、これは良い考えではありません。ストリームオプションの方が優れています。
ポールリーディ

@PaulReedyパーフェクト...しかし、多くの場合、大きなファイルを処理する必要はありません。しかし、私はあなたの主張に完全に同意します!
アンドレ・デ・マトスFerrazの

14

IHttpActionResultの中でApiController

[HttpGet]
[Route("file/{id}/")]
public IHttpActionResult GetFileForCustomer(int id)
{
    if (id == 0)
      return BadRequest();

    var file = GetFile(id);

    IHttpActionResult response;
    HttpResponseMessage responseMsg = new HttpResponseMessage(HttpStatusCode.OK);
    responseMsg.Content = new ByteArrayContent(file.SomeData);
    responseMsg.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
    responseMsg.Content.Headers.ContentDisposition.FileName = file.FileName;
    responseMsg.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
    response = ResponseMessage(responseMsg);
    return response;
}

PDFをダウンロードせず、PDFビューアに組み込まれているブラウザを使用する場合は、代わりに次の2行を削除します。

responseMsg.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
responseMsg.Content.Headers.ContentDisposition.FileName = file.FileName;

@ElbertJohnFelipeはい、でファイルを取得しますvar file = GetFile(id);file.SomeData(バイトアレイであるbyte[])とfile.FileNameなりますstring
オグラス2018

投稿ありがとうございます。「HttpResponseMessage」はApiController内では私にとって機能しなかったため、あなたは私を救った。
最大

13

注意事項.Net Core:生のバイトを送信FileContentResultするapplication/octet-stream場合は、を使用してcontentTypeをに設定できます。例:

[HttpGet("{id}")]
public IActionResult GetDocumentBytes(int id)
{
    byte[] byteArray = GetDocumentByteArray(id);
    return new FileContentResult(byteArray, "application/octet-stream");
}

1
これは、ファイル名を制御したい場合にも上の性質があり、素晴らしい作品FileContentResultと呼ばれるFileDownloadNameファイル名を指定する
weeksdevを

@weeksdevああはそれを知りませんでした。コメントをありがとう。
Amir Shirazi

それで、ありがとう。また、weeksdevからのコメントも非常に役立ちます。
フラグ

1

もっと「一般的な」方法でファイルをダウンロードする簡単な方法があるのか​​と思っていました。これを思いついた。

これActionResultは、を返すコントローラー呼び出しからファイルをダウンロードできるようにするシンプルなものですIHttpActionResult。ファイルはに保存されますbyte[] Content。必要に応じて、ストリームに変換できます。

これを使用して、データベースのvarbinary列に格納されているファイルを返しました。

    public class FileHttpActionResult : IHttpActionResult
    {
        public HttpRequestMessage Request { get; set; }

        public string FileName { get; set; }
        public string MediaType { get; set; }
        public HttpStatusCode StatusCode { get; set; }

        public byte[] Content { get; set; }

        public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
        {
            HttpResponseMessage response = new HttpResponseMessage(StatusCode);

            response.StatusCode = StatusCode;
            response.Content = new StreamContent(new MemoryStream(Content));
            response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
            response.Content.Headers.ContentDisposition.FileName = FileName;
            response.Content.Headers.ContentType = new MediaTypeHeaderValue(MediaType);

            return Task.FromResult(response);
        }
    }

コードがOPの問題をどのように修正するかを簡単に説明すると、回答の質が向上します。
エイドリアンモール
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.