web-dev-qa-db-ja.com

Return PDF

ASP.NetコアでPDFを返すWep APIを作成しました。ここに私のコードがあります:

public HttpResponseMessage Get(int id)
{
    var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);           
    var stream = new System.IO.FileStream(@"C:\Users\shoba_eswar\Documents\REquest.pdf", System.IO.FileMode.Open);
    response.Content = new StreamContent(stream);
    response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
    response.Content.Headers.ContentDisposition.FileName = "NewTab";
    response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/pdf");
    return response;
}

ただし、JSON応答のみを返します。

{
   "version":{
      "major":1,
      "minor":1,
      "build":-1,
      "revision":-1,
      "majorRevision":-1,
      "minorRevision":-1
   },
   "content":{
      "headers":[
         {
            "key":"Content-Disposition",
            "value":[
               "attachment; filename=NewTab"
            ]
         },
         {
            "key":"Content-Type",
            "value":[
               "application/pdf"
            ]
         }
      ]
   },
   "statusCode":200,
   "reasonPhrase":"OK",
   "headers":[

   ],
   "requestMessage":null,
   "isSuccessStatusCode":true
}

ここで何か間違っていますか?

17
Shoba

ASP.NET Core HTTPRequestMessageが奇妙なJSONメッセージを返す で説明されているように、ASP.NET CoreはHttpResponseMessage(そのタイプにアクセスするためにどのパッケージをインストールしましたか?)を返すことをサポートしていません。

このため、シリアライザーは、サポートされていない他の応答タイプの場合と同様に、単にHttpResponseMessageのすべてのパブリックプロパティを出力に書き込みます。

カスタム応答をサポートするには、IActionResult-実装型を返す必要があります。 それらの多く があります。あなたの場合、 FileStreamResult を調べます。

_public IActionResult Get(int id)
{
    var stream = new FileStream(@"path\to\file", FileMode.Open);
    return new FileStreamResult(stream, "application/pdf");     
}
_

または、単純にストリームを処理する PhysicalFileResult を使用します。

_public IActionResult Get(int id)
{
    return new PhysicalFileResult(@"path\to\file", "application/pdf");
}
_

もちろん、これらすべては、Controller.File()などのヘルパーメソッドを使用して単純化できます。

_public IActionResult Get(int id)
{
    var stream = new FileStream(@"path\to\file", FileMode.Open);
    return File(stream, "application/pdf", "FileDownloadName.ext");
}
_

これは、単純にFileContentResultまたはFileStreamResult(このオーバーロードの場合は後者)の作成を抽象化します。

または、古いMVCまたはWeb APIアプリケーションを変換していて、すべてのコードを一度に変換したくない場合は、 WebApiCompatShim(NuGet) への参照を追加し、現在のコードを- ResponseMessageResult

_public IActionResult Get(int id)
{
    var response = new HttpResponseMessage(HttpStatusCode.OK);           
    var stream = ...
    response.Content...

    return new ResponseMessageResult(response);
}
_

return File(fileName, contentType, fileDownloadName)を使用したくない場合、FileStreamResultは、コンストラクターまたはプロパティを介したcontent-dispositionヘッダーの設定をサポートしません。

その場合、ファイルの結果を返す前に、その応答ヘッダーを自分で応答に追加する必要があります。

_var contentDisposition = new ContentDispositionHeaderValue("attachment");
contentDisposition.SetHttpFileName("foo.txt");
Response.Headers[HeaderNames.ContentDisposition] = contentDisposition.ToString();
_
50
CodeCaster

私の評判が十分に高くないため、CodeCasterによる回答にコメントできませんでした。しようとするとき

public IActionResult Get(int id)
{
    using (var stream = new FileStream(@"path\to\file", FileMode.Open))
    {
        return File(stream, "application/pdf", "FileDownloadName.ext");
    }       
} 

私たちは

ObjectDisposedException:破棄されたオブジェクトにアクセスできません。オブジェクト名:「閉じたファイルにアクセスできません。」。 System.IO.FileStream.BeginRead(byte []配列、intオフセット、int numBytes、AsyncCallbackコールバック、オブジェクト状態)

使用を削除しました

   [HttpGet]
   [Route("getImageFile")]
   public IActionResult GetWorkbook()
   {
        var stream = new FileStream(@"pathToFile", FileMode.Open);
        return File(stream, "image/png", "image.png");
   }

そしてそれはうまくいきました。これは、IIS Expressで実行されているASP.NET Core 2.1です。

6
Bernhard Maertl

これをコメントとして投稿するほどの評判はありませんので、回答として投稿してください。 @CodeCasterの最初の3つのソリューションと@BernhardMaertlのソリューションは正しいです。

ただし、頻繁にファイルを操作しない人(私のような)の場合、このコードを実行するプロセス(APIなど)がファイルへの読み取り権限しか持たない場合は、作成時に3番目のパラメーターとして指定する必要がありますFileStream、それ以外の場合、デフォルトの動作はファイルを読み取り/書き込み用に開くことで、書き込み権限がないため例外が発生します。

@CodeCasterの3番目のソリューションは次のようになります。

public IActionResult Get(int id)
{
    var stream = new FileStream(@"path\to\file", FileMode.Open, FileAccess.Read);
    return File(stream, "application/pdf", "FileDownloadName.ext");
}