動的に生成したPDFをダウンロードするリンクを追加する

ソフトウェア開発部のIです。

PDFを動的に生成してファイルをサーバーに残さずブラウザで表示する、という機能を以前ASP.NETで実装したんですが、その表示したPDFをビュアーの機能を使って保存するのではなくPDFをダウンロードするリンクを設置する場合はどうしたらいいのかと少し調べたら、簡単な方法があったので記述例をご紹介します。

サーバーに生成したPDFは残したくないので、一時ファイルに出力したPDFをBase64に変換して返し、HTML5でa要素に追加されたdownload属性を使用して実装しました。

サーバー

[HttpPost]
public ActionResult GetPdf()
{
    // 一時ファイルパス
    string tempFileName = string.Empty;

    try
    {
        // 一時ファイルを作成する
        tempFileName = Path.GetTempFileName();
        // 一時ファイルにPdfを出力する
        CreatePdf(tempFileName);
        // Base64に変換してContentResultを返す
        using (FileStream fs = new FileStream(tempFileName, FileMode.Open))
        {
            // バイト配列を取得する
            byte[] bytes = new byte[fs.Length];
            fs.Read(bytes, 0, bytes.Length);
            fs.Close();
            // Base64に変換する
            string base64 = Convert.ToBase64String(bytes, 0, bytes.Length);
            // ContentResultを返す
            return Content(base64);
        }
    }
    catch (Exception)
    {
        throw;
    }
    finally
    {
        // 一時ファイルを削除する
        if (System.IO.File.Exists(tempFileName))
        {
            System.IO.File.Delete(tempFileName);
        }
    }
}

一時ファイルにPDFを出力してBase64に変換しContentResultで返します。一時ファイルとして出力したPDFファイルは残さないので最後に削除します。
ここでは省略しましたがPDFファイルの生成部分には「シーオーリポーツ」を使用しています。体験版もありますのでお試しください。

クライアント

$.ajax({
    url: '@Url.Action(アクション名, コントローラー名)',
    type: "POST",
    cache: false,
    async: true,
}).done(function (data) {
    $(document.body).append($("<a>").attr("download", "test.pdf").attr("href", "data:application/pdf;base64," + data).text("ダウンロード"));

}).fail(function () {
    alert("PDFの取得に失敗");
});

ajaxでBase64に変換したPDFファイルを取得し、bodyにダウンロードのリンクを追加しています。

<a download="test.pdf" href="data:application/pdf;base64,~~">ダウンロード</a>

a要素でdownload属性に保存時のファイル名、href属性に "data:application/pdf;base64," + Base64に変換したPDF という形で記述するだけで簡単にダウンロードのリンクを生成することが出来ました。