🐥note.

小鳥とMicrosoft <3 なエンジニアの技術Blog📚

ASP.NET Core Update in .NET Core 3.1 Preview2の新機能について

Microsoft Igniteで盛り上がるIT界の裏では.NET Core 3.1 Preview2がリリースされました。

devblogs.microsoft.com

それに合わせてASP.NET CoreとEntityFramework CoreもPreviewが公開されています。

devblogs.microsoft.com

本エントリではASP.NET Coreに追加された新機能について個人的にまとめます。

新機能について

上記公式Blogから抜粋

  • New component tag helper
  • Prevent default actions for events in Blazor apps
  • Stop event propagation in Blazor apps
  • Validation of nested models in Blazor forms
  • Detailed errors during Blazor app development

詳しく見ていきます。

New component tag helper

以前はRenderComponentAsyncHTMLヘルパーを使用して、ビューまたはページからコンポーネントレンダリングしていました。

@(await Html.RenderComponentAsync<Counter>(RenderMode.ServerPrerendered, new { IncrementAmount = 10 }))

新しいコンポーネントタグヘルパーは以下の通り。

<component type="typeof(Counter)" render-mode="ServerPrerendered" param-IncrementAmount="10" />

レンダリングするComponentのTypeと、レンダーモードを指定します。 また、Componentに対するParameterをparam-句で指定できるようになりました。

それに伴いBlazorのTemplateで作成される_Host.cshtmlの内容が変化しています。

<!-- 途中省略 -->
<body>
    <app>
-        @(await Html.RenderComponentAsync<App>(RenderMode.ServerPrerendered))
+        <component type="typeof(App)" render-mode="ServerPrerendered" />
    </app>

    <script src="_framework/blazor.server.js"></script>
</body>
</html>

componentを使うよう変化していますね。

Blazorに限ると_Host.cshtml以外から使うことってあるのでしょうか...?
よく分かりません。

Prevent default actions for events in Blazor apps

@oneventname:preventDefault ディレクティブ属性を使用して、BlazorアプリのEventのデフォルトアクションを防止できるようになりました。

私は今まではRazor内に普通にJavaScript関数として記述していました。こんな感じです。
ondragoverは@なしなので、JavaScriptの関数です。

<div ondragover="event.preventDefault()" @ondrop="@OnDrop">
    ...
</div>

今回の変更で@つきのディレクティブ属性になったので、書き方に統一感が出ましたね。
変更後はこんな感じに書けるようです。

<div @ondragover:preventDefault @ondrop="@OnDrop">
    ...
</div>

Stop event propagation in Blazor apps

@oneventname:stopPropagationディレクティブ属性を使用して、Blazorアプリでイベントの伝播を停止します。
次の例では、チェックボックスをオンにすると、子divからのクリックイベントが親に伝播しなくなります。

<input @bind="stopPropagation" type="checkbox" />
<div @onclick="OnClickParentDiv">
    Parent div
    <div @onclick="OnClickChildDiv" @onclick:stopPropagation="stopPropagation">
        Child div
    </div>
</div>

<button @onclick="OnClick">Click me!</button>

@code {
    bool stopPropagation;

    void OnClickParentDiv() => Console.WriteLine("Parent div clicked.");
    void OnClickChildDiv() => Console.WriteLine("Child div clicked.");
}

これ地味にめっちゃありがたいやつでは?

Validation of nested models in Blazor forms

検証対象のModel内に存在するクラスのプロパティの検証ができるようになった感じでしょうか?

探したところ、こちらにサンプルが上がっていました。

github.com

MergeされたPRはこちらでしょうか?

github.com

サンプルを見た感じ、ObjectGraphDataAnnotationsValidatorValidateComplexType属性がキモなのかな?

Person.cs

using System.ComponentModel.DataAnnotations;

namespace Validation.Data
{
    public class Person
    {
        [Required]
        public string Name { get; set; }

        [ValidateComplexType]
        public Address Address { get; set; } = new Address();

        [ValidateComplexType]
        public PhoneNumber[] PhoneNumbers { get; set; } = new[]
        {
            new PhoneNumber(),
            new PhoneNumber(),
        };
    }
}

ValidateComplexType属性を付与された側のClass(AddressとPhoneNumberクラス)は特に意識する必要はないようです。

PhoneNumber.cs

using System.ComponentModel.DataAnnotations;

namespace Validation.Data
{
    public class PhoneNumber
    {
        public string Description { get; set; }

        [Required]
        public string Number { get; set; }
    }
}

使用するにはMicrosoft.AspNetCore.Blazor.DataAnnotations.Validationというパッケージが必要のようです。
インストール時の注意としては--version指定をしなければインストールできませんでした。

Nugetはこちら

www.nuget.org

dotnet add package Microsoft.AspNetCore.Blazor.DataAnnotations.Validation --version 3.1.0-preview2.19528.8

Microsoft.AspNetCore.Blazor.DataAnnotations.Validationは実験的な位置づけであり今のところ.NET Core 3.1に同封する計画はないそうです。

Detailed errors during Blazor app development

TagHelperの件も相まってTemplateが更新されました。

github.com

...
<body>
    <app>
        <component type="typeof(App)" render-mode="ServerPrerendered" />
    </app>

    <div id="blazor-error-ui">
        <environment include="Staging,Production">
            An error has occurred. This application may no longer respond until reloaded.
        </environment>
        <environment include="Development">
            An unhandled exception has occurred. See browser dev tools for details.
        </environment>
        <a href class="reload">Reload</a>
        <a class="dismiss">🗙</a>
    </div>

    <script src="_framework/blazor.server.js"></script>
</body>
</html>

エラー発生時の画面に関するブロックが追加されていますね!

どんな感じにメッセージが出力されるのか、Develop環境で例外を投げてみます。

画面下部の黄色い帯がエラーメッセージ部分です。
メッセージの通り、ChromeのDeveloper Toolには例外の内容が吐かれています。

f:id:piyo_esq:20191105201542p:plain
Develope環境で例外をthrow

続いてProduction環境です。

f:id:piyo_esq:20191105201621p:plain
Production環境で例外をthrow

Developer Toolで表示されているメッセージの通りappsetting.jsonDetailedErrorstrueに設定してみます。

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
+ "DetailedErrors": true
}

または、Statrup.csを以下のように変更します。

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();
-   services.AddServerSideBlazor();
+   services.AddServerSideBlazor().AddCircuitOptions(option =>
+   {
+       option.DetailedErrors = true;
+   });
    services.AddSingleton<WeatherForecastService>();
}

例外を投げます。
Production環境なのに例外を吐くやばい感じなりました。

f:id:piyo_esq:20191105201653p:plain
Production環境で例外が見れちゃう

おわり

Templateがアプデされてエラー画面が簡単に書けるようになったの非常に良いですね。

@{eventName}:stopPropagationも何かと便利ですし、何よりValidateComplexTypeによる検証が楽しみですね。