19
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

BlazorAdvent Calendar 2019

Day 9

Blazorを使うのであれば早めに例外対応をするのがオススメ

Posted at

この内容は Blazor Advent Calendar 2019の9日目の記事です

#最初は例外なんて考えずバリバリ作る人もBlazorでは例外対応をしよう!
Blazorを使うなら早めの例外対応をお進めします。特に最初は例外とか深く考えず、バリバリ作ってみるタイプの人でもやった方が良いと思います。実際、僕も新しい技術をさわる際に言語仕様を読み込んだり、例外を意識したプログラムを書いたりは殆どしない方です。まずサンプルさわってみて、そのサンプルを自分の作っているものに当て込んで、そこからバリバリ作って、色々落ち着いてきてから初めて例外を意識しました。でも、ことBlazorに関してはそこまで例外をほったらかしたのは、結構な時間を無駄にしたと感じました。

#Blazorのサンプル通りに作っていく場合の典型的な進め方
Blazorでデータベースなどから値を取得する場合、サンプルを参考にするならWebAPI経由で値を取ってくる形になると思います。

    protected override async Task OnInitAsync()
    {
        //GetJsonAsyncでサーバーから値を取得
        forecasts = await Http.GetJsonAsync<WeatherForecast[]>("api/SampleData/WeatherForecasts");
    }

で、html側は値が取れるまでLoadingを表示していて、取れたらその値を表示するプログラムになると思います。

    @if (forecasts == null) //←値が取れない時はローディング表示
    {
        <p><em>Loading...</em></p>
    }
    else                    //←値が取れたらその値を表示
    {
        @foreach (var forecast in forecasts)
        {
            <tr>
                <td>@forecast.Date.ToShortDateString()</td>
            </tr>
        }
    }

実際僕もこの作りのままで自作サービスを作り続けていました。

#この状態で例外が起きると
さて開発中は色々例外が起きます。例えばURLの打ち間違えとか、インターネットにつなげない状態でアクセスするとか、単純な実装ミスとか。そうなるとどうなるか。GetJsonAsyncで例外が出てforecastsnullのままになります。

    forecasts = await Http.GetJsonAsync<WeatherForecast[]>("api/SampleData/WeatherForecasts");

つまりhtmlはずーっとローディング表示になります。

    @if (forecasts == null) //←値が取れない時はローディング表示
    {
        <p><em>Loading...</em></p>
    }

例外が起きている時=ローディングから次に進まない時です。これではローディング画面がいつもより長いなと思うまで例外と気づきません。またどこで例外が起きたかも分かりません。開発者ツールを使えばサーバー側の例外は分かりますが、クライアント側の例外の場所は特定できません。Windowsの開発なら例外が出た時点でVisual Studioが勝手に実行時例外が出る箇所を捕まえてくれます。この環境でしか開発したことがなかったので、自分で例外に対して何かするのは思いもしなかったというのが正直なところです。でもBlazorは現在実行時例外が起きても特に何もしてくれません。

#Blazorでの例外対応
で、対応ですが、一番のオススメは(特に開発中であれば)、エラーページに飛ばしてそのページに例外のスタックトレースを書いてしまうことです。その際少しはまったので、コツを書きます。先ずHttp.GetJsonAsyncを例外で囲んで、例外が起きたらNavigationManager.NavigateToでエラーページに飛ばします。例外のメッセージをパラメータに投げる際にはWebUtility.UrlEncodeしましょう。これでエラーページにパラメータで例外内容を渡します。

        try
        {
            forecasts = await Http.GetJsonAsync<WeatherForecast[]>("api/SampleData/WeatherForecasts");
        }
        catch (Exception ex)
        {
            NavigationManager.NavigateTo(WebUtility.UrlEncode($"error?message=" + ex.Message + Environment.NewLine + ex.StackTrace));
            throw;
        }

そしてエラーページで、パラメータを表示する際にWebUtility.UrlDecodeします。このままだとスタックトレースが改行されずに表示するので\nから<br>に置き換えます。

    protected override void OnInitialized()
    {
        var url = NavigationManager.Uri;
        Message = WebUtility.UrlDecode(url.ToValue("message"));
        Message = Message.Replace("\n", "<br>");
    }

さらにhtmlに書く際に、@((MarkupString)Message)してマークアップ文字をそのまま表示してやります。

    <div>
        <h1>ERROR</h1>
        @((MarkupString)Message)
        <br>
        <br>
        <a href="/">Topに戻る</a>
    </div>

そうするとこんな感じで例外が表示されます。例外によっては戻るボタンでは永遠に戻れないことがある(例外が解消していなければまた例外が起きて、同じページに飛ぶ)のでTOPに戻るリンクも用意すると良いと思います。
error.png

これでOKです。さあ、あとはバリバリ作りましょう!

この内容はゴミ箱行き?

asp.net core 3.1が出て、最新のBlazorのポストを見たらAttach to process debugging from Visual Studioという一言がありました。ここに書いた内容はもういらなくなるかもと思ったですが、少なくとも何も考えずに未設定でattach出来るわけではなさそうでした。分かったら追記するかも。

19
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?