WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

input type="file" を生成してアップロード

by WebSurfer 2023年4月2日 20:46

JavaScript を使って、ボタンクリックでファイル選択ダイアログを表示し、ユーザーがダイアログに表示されたファイルを選択したら即アップロードする方法を書きます。

ファイルアップロード

ファイルのアップロードでよくあるパターンは、<form> 要素の中に <input type="file"> 要素と <input type="submit"> 要素を静的に配置しておいて、(1) <input type="file"> のファイル選択ボタンをクリックしてファイル選択ダイアログを表示、(2) ユーザーがダイアログからファイルを選択、(3) <input type="submit"> をクリックして選択されたファイルを POST 送信する・・・というものだと思います。

その (1) から (3) のステップを短縮し、<input type="button"> ボタンをクリックしたらファイル選択ダイアログを表示し、ユーザーがファイルを選択したら File API を利用して File オブジェクトを取得し、それを fetch API を使って即 Web API にアップロードしてみます。

クライアント側のコードは以下の通りです。<input type="button"> ボタンだけを静的に配置しておき、それ以外は JavaScript で処置しています。説明はコード内のコメントに書きましたのでそれを見てください。

コードは ASP.NET Core MVC の View をものをそのままコピー&ペーストしましたが、その中の html と JavaScript のコードはどのような Web アプリにも使えるはずです。

@{
    ViewData["Title"] = "UploadFile";
}

<h1>UploadFile</h1>

<button type="button" class="btn btn-primary" id="btn">
    ファイル選択してアップロード
</button>

<div id="result"></div>

@section Scripts {
   <script type="text/javascript">
        window.addEventListener('DOMContentLoaded', () => {

            // Promise を返す非同期メソッド
            const showOpenFileDialog = async () => {
                return new Promise(resolve => {
                    // input type="file" 要素を動的に生成、
                    const input = document.createElement('input');
                    input.type = 'file';

                    // .jpg ファイルのみ選択できるよう設定してみた
                    input.accept = '.jpg';

                    // ユーザーがファイルを選択すると change イベント
                    // が発生するのでそれにリスナをアタッチし、File
                    // オブジェクトを取得。それを Promise の resolve
                    // コールバックに設定
                    input.addEventListener('change', 
                            e => resolve(e.target.files[0]));

                    // クリックしてファイル選択ダイアログを開く
                    input.click();
                });
            };

            // ボタンクリックで上のメソッドを呼び出し File オブジェ
            // クトを取得。それを fetch API を使って Web API に送信
            document.getElementById("btn")
                    .addEventListener('click', async () => {
                const file = await showOpenFileDialog();
                const formData = new FormData();
                formData.append("postedFile", file);
                const param = {
                    method: "POST",
                    body: formData
                }
                const response = await fetch("/api/Upload", param);
                const data = await response.text();
                document.getElementById("result").innerText = data;
            });
        });
   </script>
}

サーバー側で、アップロードされてきたファイルを受けて保存する ASP.NET Core Web API のコードも参考までに以下に載せておきます。

using Microsoft.AspNetCore.Mvc;

namespace MvcCore6App3.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class UploadController : ControllerBase
    {
        // 物理パスの取得用
        private readonly IWebHostEnvironment _hostingEnvironment;

        public UploadController(IWebHostEnvironment hostingEnvironment)
        {
            this._hostingEnvironment = hostingEnvironment;
        }

        // .NET 6.0 で作ったプロジェクトは「Null 許容」オプションが「有効化」
        // に設定してあるので、引数も null 許容にしておかないと、クライアント
        // でファイルを選択しないで送信した場合、HTTP 400 Bad Request エラー
        // になって "The postedFile field is required."というエラーメッセージ
        // が返ってくる
        [HttpPost]
        public async Task<string> Post([FromForm] IFormFile? postedFile)
        {
            string result = "";
            if (postedFile != null && postedFile.Length > 0)
            {
                // アップロードされたファイル名を取得
                string filename = System.IO.Path.GetFileName(postedFile.FileName);

                // アプリケーションルートの物理パスを取得
                string contentRootPath = _hostingEnvironment.ContentRootPath;

                string filePath = $"{contentRootPath}\\UploadedFiles\\" +
                    $"{filename}{DateTime.Now.ToString("yyyyMMddHHmmss")}.jpg";

                // フォルダ UploadedFile に画像ファイルを保存
                using (var stream = new FileStream(filePath, FileMode.Create))
                {
                    await postedFile.CopyToAsync(stream);
                }

                result = $"{filename} ({postedFile.ContentType}) - " +
                    $"{postedFile.Length} bytes アップロード完了";
            }
            else
            {
                result = "ファイルアップロードに失敗しました";
            }

            return result;
        }
    }
}

Tags: , , ,

Upload Download

dotnet dev-certs https コマンドについて

by WebSurfer 2023年3月30日 21:43

dotnet dev-certs https コマンドについて調べたことを備忘録として残しておきます。

dotnet dev-certs コマンド

dotnet dev-certs コマンドは、Microsoft のドキュメント dotnet dev-certs に書いてありますように、開発用のサーバー証明書の作成・管理を行うためのツールです。

具体的には、フレンドリ名が ASP.NET Core HTTPS development certificate という自己署名証明書を作成・管理するツールです。その証明書を使って、ASP.NET Core Web アプリの開発中に、Web サーバーの Kestrel がブラウザなどのクライアントと HTTPS 通信ができるようになります。

(注: IIS Express でホストする場合は IIS Express Development Certificate というフレンドリ名の証明書が使用されます。このスレッドの話は関係ないので注意してください。)

このコマンドの実行によって証明書マネージャーに表示される証明書がどのようになるか、証明書がないときアプリを Kestrel で動かそうとするとどうなるかも以下に合わせて書いておきます。

(1) 初期状態

Visual Studio を開発に使っていれば自力で dotnet dev-certs コマンドを打って証明書を作る必要はなく、Visual Studio がコマンドを使って必要な証明書を生成してくれます。下の証明書マネージャーの画像がその結果で、発行先が localhost となっているのが開発用サーバー証明書です。

開発用サーバー証明書

有効期限切れのものが含まれていますが (何年か Visual Studio で作業しているうちに追加されたものです)、作業していて支障はなかったのでそのままにしていました。

この中のフレンドリ名 ASP.NET Core HTTPS development certificate という証明書をすべて削除してから、新しく証明書を作成し、開発環境でそれを使って HTTPS 通信ができるようにします。

(2) dotnet dev-certs https --clean 実行

既存の証明書を削除するためコマンドラインから dotnet dev-certs https --clean を実行します。

コマンドを打つと下の画像の「ルート証明書ストア」というダイアログが出て削除してよいかが確認されるので[はい]をクリックします。(上の画像のように複数証明書がある場合は複数回ダイアログが出ます)

「ルート証明書ストア」ダイアログ

削除に成功するとコマンドラインに "HTTPS development certificates successfully removed from the machine." と表示され、証明書マネージャーの[個人]>[証明書]および[信頼されたルート証明書]>[証明書]にあったフレンドリ名 ASP.NET Core HTTPS development certificate の証明書はすべて削除されます。

(IIS Express 用の証明書 IIS Express Development Certificate にはこのコマンドは影響ありません)

この状態でコマンドラインから dotnet dev-certs https --check を実行すると "No valid certificate found." と表示されます。

(3) アプリの実行

証明書を削除した後、Visual Studio 2022 で Kestrel を使って ASP.NET Core Web アプリを実行すると「ASP.NET Core SSL 証明書を信頼する」というダイアログが出ます。

ASP.NET Core SSL 証明書を信頼する

[いいえ]を選択すると下の画像のダイアログが出て「Web サーバー 'MvcCore6App2' に接続できません。Web サーバーはもう実行されてません」というメッセージが表示されて終わってしまいます。

ダイアログ

コンソールを見ると以下の例外が出ていました。

Unhandled exception. System.InvalidOperationException: Unable to configure HTTPS endpoint. No server certificate was specified, and the default developer certificate could not be found or is out of date. To generate a developer certificate run 'dotnet dev-certs https'. To trust the certificate (Windows and macOS only) run 'dotnet dev-certs https --trust'.

(IIS Express 用の証明書 IIS Express Development Certificate には影響はありませんので、Visual Studio 2022 の設定を IIS Express を使うようにしてアプリを実行すれば上のような問題はありません)

(4) dotnet dev-certs https 実行

証明書を作成するためコマンドラインから dotnet dev-certs https を実行します。作成に成功すると "The HTTPS developer certificate was generated successfully." というメッセージが表示されます。

証明書マネージャーを見ると[個人]>[証明書]にフレンドリ名 ASP.NET Core HTTPS development certificate という証明書が追加されています。

証明書マネージャー

ただし、この時点では[信頼されたルート証明書]>[証明書]には ASP.NET Core HTTPS development certificate は存在しません。

この状態で上の (3) と同様にアプリを実行してみます。同じく「ASP.NET Core SSL 証明書を信頼する」というダイアログが出るので[いいえ]を選択すると、今度は InvalidOperationException 例外はスローされず、自己署名証明書を使った場合の警告がブラウザに表示されます。

プライバシーエラー

警告を無視して進めればブラウザにコンテンツの表示はできます。

(5) dotnet dev-certs https --check 実行

コマンドラインから dotnet dev-certs --check を実行しても証明書が発行されたかどうかを確認できます。発行されていると以下のようなメッセージが返ってきます。

A valid certificate was found: 8216607E62A7221B7EFEC3022C8AD599DC1728B1 - CN=localhost - Valid from 2023-03-28 13:07:39Z to 2024-03-27 13:07:39Z - IsHttpsDevelopmentCertificate: true - IsExportable: true
Run the command with both --check and --trust options to ensure that the certificate is not only valid but also trusted.

このコマンドは証明書の情報を確認するためだけのものです。証明書を作成することもなく、作成済みの証明書には何も影響しません。

(6) dotnet dev-certs https --trust 実行

上の (4) で発行した証明書を「信頼されたルート証明書」として登録するため、コマンドラインから dotnet dev-certs https --trust を実行します。

コマンドを入力すると、コマンドラインには "Trusting the HTTPS development certificate was requested. A confirmation prompt will be displayed if the certificate was not previously trusted. Click yes on the prompt to trust the certificate." というメッセージが表示され、下の画像のセキュリティ警告ダイアログが表示されます。

セキュリティ警告ダイアログ

[はい]をクリックして処理を継続します。成功するとコマンドラインには "Successfully trusted the existing HTTPS certificate." というメッセージが表示されます。

証明書マネージャーを見ると[信頼されたルート証明書]>[証明書]に ASP.NET Core HTTPS development certificate が追加されています。

証明書マネージャー

この後で Visual Studio からアプリを実行すれば証明書の問題はなくなり HTTPS 通信を使っての開発ができるようになります。

Tags: , , , ,

CORE

Blazor アプリで Bootstrap5 Modal の利用

by WebSurfer 2023年3月11日 14:09

Blazor アプリで Bootstrap5 の Modal を使う方法を書きます。この記事では Visaul Studio 2022 のテンプレートで作った .NET 6.0 の Blazor Web Assembly を例に使います。(Blazor Server でもほぼ同じようにしてできます)

Blazor アプリで Bootstrap Modal

Bootstrap5 Modal の詳しい説明は Bootstrap のドキュメント「Modal (モーダル)」にあります。普通の html + css + javascript のページに Bootstrap5 Modal を組み込むなら、そのドキュメントから十分な情報が得られると思います。

JavaScript のメソッドを呼び出すのがいろいろややこしい Blazor アプリに、Bootstrap5 Modal を組み込むにはどうしたらいいかというのががこの記事のポイントで、それを以下に述べます。

Visaul Studio 2022 のテンプレートで作った .NET 6.0 の Blazor アプリには bootstrap.min.css v5.1.0 が組み込み済みです。ただし、それだけでは Modal は使えません。使うには bootstrap.js が必要なので同じバージョンのものを wwwroot 下に追加します。

加えて、JavaScript で Modal を表示するためのコードを含んだ外部スクリプトファイルを作成します。内容は以下の通りです。Bootstrap のドキュメント「Via JavaScript」を参考にしました。ファイル名は exampleJsInterop.js としています (名前は任意)。

window.showBootstrapModal = () => {
    // staticBackdrop は modal 表示する div 要素の id
    let divModal = document.getElementById('staticBackdrop');
    let myModal = new bootstrap.Modal(divModal);
    myModal.show();
}

Modal を表示するには、Bootstrap のドキュメント「Via data attributes」に書かれているように、表示に必要な属性を付与した button のような要素を使う方法もあります。その方法で良ければ、上のスクリプトファイル exampleJsInterop.js は不要です。ただし、その場合でも bootstrap.js は必要ですので注意してください。

bootstrap.js ファイルと exampleJsInterop.js ファイルを wwwroot 下に配置し、wwwroot/index.html にそのファイルへの参照を追加します。下の画像の赤枠を見てください。青枠は既存の bootstrap.min.css のものです。

外部スクリプトファイルの追加

Bootstrap5 は jQuery に依存していないそうですので jquery.js は不要です。(上の画像では jquery.js も追加されていますが、Bootstrap5 とは関係ない別の目的です)

Blazor Sever の場合、外部スクリプトファイル bootstrap.js と exampleJsInterop.js への参照を追加するのは Pages/_Layout.cshtml になります。そこだけが Blazor Web Assembly と Blazor Server の違いです。

Pages フォルダ下に Razor コンポーネントを追加し、それに Bootstrap のドキュメント「Live demo」のコードをコピーします。それだけで[Launch static backdrop modal]ボタンをクリックすると Modal が表示されるようになります。

Blazor アプリで Bootstrap Modal

JavaScript で Modal を表示するには、外部スクリプトファイル exampleJsInterop.js の showBootstrapModal メソッドを呼び出してやります。それを含めた Razor コンポーネント全体のコードは以下のようになります。

[Via JavaScript]ボタンに設定した @onclick="ShowBootstrapModal" で @code 内の ShowBootstrapModal メソッドを呼び出し、その中の InvokeVoidAsync メソッドで showBootstrapModal メソッドを呼び出しています。

@page "/modal"
@inject IJSRuntime JSRuntime;

<PageTitle>Bootstrap Modal</PageTitle>

<!-- Modal -->
<div class="modal fade" 
    id="staticBackdrop" 
    data-bs-backdrop="static" 
    data-bs-keyboard="false" tabindex="-1" 
    aria-labelledby="staticBackdropLabel" 
    aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" 
                    id="staticBackdropLabel">
                    Modal title
                </h5>
                <button type="button" 
                    class="btn-close" 
                    data-bs-dismiss="modal" 
                    aria-label="Close">
                </button>
            </div>
            <div class="modal-body">
                ...
            </div>
            <div class="modal-footer">
                <button type="button" 
                    class="btn btn-secondary" 
                    data-bs-dismiss="modal">
                    Close
                </button>
                <button type="button" 
                    class="btn btn-primary">
                    Understood
                </button>
            </div>
        </div>
    </div>
</div>

<h1>Bootstrap Modal</h1>

<!-- Via JavaScript -->
<button type="button" class="btn btn-primary" 
    @onclick="ShowBootstrapModal">
    Via JavaScript
</button>

<br />
<br />

<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" 
    data-bs-toggle="modal" 
    data-bs-target="#staticBackdrop">
    Launch static backdrop modal
</button>

@code {
    private async Task ShowBootstrapModal()
    {
        await JSRuntime
            .InvokeVoidAsync("showBootstrapModal");
    }
}

JavaScript のメソッドを呼び出す方法の詳細は Microsoft のドキュメント「ASP.NET Core Blazor で .NET メソッドから JavaScript 関数を呼び出す」に書かれていますので興味がありましたら読んでください。

Tags: , ,

CORE

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年4月  >>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar