個人的なメモ

Tomohiro Suzuki @hiro128_777 のブログです。Xamarin に関する事を中心に書いています。 Microsoft MVP for Development Technologies 2017- 本ブログと所属組織の公式見解は関係ございません。

ASP.NET Core Update(.NET 6)の整理(随時更新中)

.NET 6 の RC 2 がリリースされました。ASP.NET Core についても Preview 1 から RC 2 まで段階的に情報や新機能がリリースされており、情報が分散して探しにくいので重要な更新情報を整理してみました。
  
公式情報も更新されているため、内容は随時更新中です。
 
.NET 6 の更新情報は以下をご覧ください。
hiro128.hatenablog.jp
 
 

 
 

Minimal API の導入(.NET 6 Preview 4)

公式情報:
Introducing minimal APIs
関連記事:
hiro128.hatenablog.jp
 

Minimal API のアップデート(.NET 6 RC 2)

Minimal API に対し、以下のいくつかのアップデートがあります。
公式情報:Minimal API updates
 

パラメータのバインディングの対応強化(.NET 6 RC 2)

  • TryParseBindAsync に継承されたメソッドに対するサポートを追加
  • パブリックの TryParseBindAsync メソッドが正しい形式かどうかをチェックする機能が追加
  • これらのメソッドに間違った構文を使っている場合エラーがスローされるようになった
  • カスタムタイプにルート、ヘッダ属性、およびクエリ文字列から値をバインドしたい場合、カスタムタイプに静的な TryParse メソッドを追加することができる

公式情報:Parameter Binding
 

OpenAPI の対応強化(.NET 6 RC 2)

  • Accepts() 拡張メソッドや [Consumes(typeof(Todo), "application/json", IsRequired = false)] 属性を使って、リクエストボディが必須かどうかを記述できる
  • Accepts 拡張メソッドとConsumes 属性で、生成された open-api docs に対して、Todo タイプと application/json の両方を表現することができる。

公式情報:OpenAPI
 

ソースコードの分析(.NET 6 RC 2)
  • ルートハンドラの問題を素早く発見したり、ミドルウェアの設定ミスを警告したりするためのアナライザを追加
  • アナライザは、WebApplicationBuilderミドルウェアの順序を検証し、誤ったミドルウェアの構成や順序が検出された場合に警告する
  • IActionResult を実装した型がルートハンドラから返された場合に検出し、結果が意図せずに JSON としてシリアル化された場合に警告する機能を追加

公式情報:Source Code Analysis
 

APIの名前変更(破壊的変更)(.NET 6 RC 2)

  • 意図を適切に説明するために以下のAPIの名称を変更した。
    • DelegateEndpointConventionBuilder -> RouteHandlerBuilder
    • OpenApiDelegateEndpointConventionBuilderExtensions -> OpenApiRouteHandlerBuilderExtensions
    • DelegateEndpointRouteBuilderExtensions は、既存のEndpointRouteBuilderExtensions と統合した。

(上記の変更により、DelegateEndpointRouteHandlerに置き換え、クラス名のConventionを削除した)

公式情報:Breaking Changes (APIs Renames)
 

非同期ストリーミング(.NET 6 Preview 4)

  • コントローラのアクションからレスポンスのJSONフォーマッタに至るまで、非同期ストリーミングがサポートされるようになった
  • アクションからIAsyncEnumerableを返しても、レスポンスの内容が送信される前にメモリにバッファリングされなくなった
  • 非同期に列挙できる大規模なデータセットを返す際のメモリ使用量が削減される

公式情報:Async streaming
 

HTTP logging ミドルウェア(.NET 6 Preview 4)

  • HTTPリクエストとHTTPレスポンスの情報(ヘッダーとボディ全体を含む)を記録する、新しい組み込みミドルウェア
  • HTTP logging は以下のログを提供する
    • HTTP リクエスト情報
    • 共通のプロパティ
    • ヘッダー
    • ボディ
    • HTTP レスポンス情報

公式情報:HTTP logging middleware
 

.NET MAUI Update の整理(随時更新中)

.NET MAUI の Preview 9 がリリースされました。Preview 1 から Preview 9 まで段階的に情報や新機能がリリースされており、情報が分散して探しにくいので重要な更新情報を整理してみました。
  
公式情報も更新されているため、内容は随時更新中です。
 
.NET 6 の新機能の情報は以下をご覧ください。
hiro128.hatenablog.jp
 
 

  

.NET MAUI の GA の時期の遅延ついて(.NET MAUI Preview 8)

  • .NET MAUI の RC は2022年第1四半期に、GA は 2022年第2四半期の初めを目標とすることに延期された。
  • Xamarin は引き続き強化され、本番用のモバイルアプリの構築には Xamarin が推奨となる。
  • .NET MAUIで提供される予定のすべての機能は、.NET 6 がGAされる2021年11月にプレビューとして利用可能になる。
  • その後は、引き続き品質向上やユーザーからのフィードバックへの対応に取り組む。
  • .NET MAUIのプレビューは毎月リリースし続ける。

公式情報:Update on .NET Multi-platform App UI (.NET MAUI) - .NET Blog
 

Visual Studio 2022 との統合(.NET MAUI Preview 8 / Visual Studio 2022 Preview 4)

  • Visual Studio 2022 Preview 4 以降のインストール時に、「.NET によるモバイル開発」ワークロード内の.NET MAUI(プレビュー)をチェックできるようになり、.NET 6とオプションのワークロードの依存関係が導入されるようになった。

公式情報:Visual Studio 2022 Preview 4 Productivity
 

MAUI アプリの起動方法の更新(.NET MAUI Preview 8)

  • MAUI アプリの起動方法が更新され、各プラットフォームでは、MauiProgram.CreateMauiAppを呼び出すようになった。

公式情報:.NET MAUI SDK Updates
 

Android のアップデート(.NET MAUI Preview 8)

  • Android 向けにビルドされた .NET 6 アプリケーションでは、Android 12(API 31)がデフォルトになる。
  • Android 12 を使用するには、JDK 11 を手動でインストールする必要があるが、Visual StudioAndroid ツールが JDK 11 をサポートするまでの間、Android デザイナー、SDK マネージャー、デバイスマネージャーに好ましくない影響を与える可能性がある。
  • Visual StudioAndroidツール が JDK 11 を使用するように更新されたら、JDK 11 を .NET MAUI にデフォルトでバンドルする。
  • Androidプロジェクトでは、デフォルトで MaterialTheme が使用されるようになった。
  • これにより、Android でランタイムエラーが発生する場合は、Platforms/Android/MainActivity.cs で @style/Maui.SplashTheme が指定されていることを確認。
  • 更新された .NET MAUIテンプレートが参考になる。

公式情報:Android Updates
 

高速な Android のスタートアップ(.NET MAUI Preview 9)

  • Preview 9には、.NET MAUIのスタートアップトレースプロファイルが同梱されており、コマンドラインからビルドする際に使用することができる。
  • スタートアップトレースを活用して起動時の実行経路を追跡することで、アプリケーションの起動時に実行される部分のみを AOT 化し、スピードとサイズのバランスを取ることができる。

公式情報:Quick Android Startup
  

コントロールの更新(.NET MAUI Preview 9)

 

新しいレイアウト(.NET MAUI Preview 7)

  • 新しいレイアウトはデフォルトで有効になっている。
  • 新しいレイアウトは 7 年間の Xamarin.Forms のレイアウトから得た知見を採用した新しい LayoutManager アプローチに基づいて、一貫性、パフォーマンス、メンテナンス性が最適化されている。
  • 従来の Xamarin.Forms のレイアウトは、Xamarin.Formsからの移行プロジェクトとの互換性のために Microsoft.Maui.Controls.Compatibility 名前空間にのみ存在するようになった。

公式情報:New Layouts
 

新しいボーダーコントロール(.NET MAUI Preview 9)

  • 新しい Microsoft.Maui.Graphics ライブラリは、ネイティブのグラフィックスエンジンに基づいた一貫した UI 描画 API を提供する。
  • .NET MAUI のほとんどのレイアウトやコントロールに、ボーダー、コーナーレンダリング、美しいシャドウを簡単に追加できる。
  • 新しいボーダーコントロールは、任意のレイアウトやコントロールをラップして、ボーダーや各コーナーの独立した制御を追加することができる。

公式情報:Borders, Corners, and Shadows – Oh my!
 

アクセシビリティの変更と改善(.NET MAUI Preview 7)

TabIndex および IsTabStop の削除(.NET MAUI Preview 7)

  • TabIndex と IsTabStopプロパティは、開発者がスクリーンリーダーで読まれるUI要素の順序を制御するために Xamarin.Forms で導入されたが、実際には混乱を招きニーズを満たしていなかった。.
  • .NET MAUI では、インターフェイスの構造をプログラムで操作する方法を探すのではなく、読まれたいようにUIを順序付ける、巧みな設計アプローチを推奨している。
  • .NET MAUI で順番をコントロールしなければならない場合には、コミュニティツールキットの SemanticOrderView を推奨する。

公式情報:TabIndex and IsTabStop Removed
 

SetSemanticFocus とアナウンス(.NET MAUI Preview 7)

  • 新しい SemanticExtensions クラスの一部として、スクリーンリーダーのフォーカスを特定の要素に移動させることができるように、新しい SetSemanticFocus メソッドが追加された。

公式情報:SetSemanticFocus and Announce
 

フォントスケーリング(.NET MAUI Preview 7)

  • すべてのプラットフォームのすべてのコントロールで、フォント・スケーリングがデフォルトで有効になった。
  • これにより、OS 上でテキストスケーリングの設定を調整すると、その設定がアプリケーションの UI に反映され、デフォルトでよりアクセシブルなアプリケーションが実現する。

公式情報:Font Scaling
 

その他の注目すべき変更と追加

.NET MAUI Preview 8

公式情報:Other Changes

  • MinHeightRequest, MaxHeightRequest, MinWidthRequest, MaxWidthRequestに "Request "という接尾辞がなくなり、レイアウトシステムがそれらを真の値として扱うようになりなった。
  • 任意のコントロールマッパーにビヘイビアを追加する方法を簡素化- #1859
  • シェルテーマのスタイリングの様々な改善
  • Android #2027iOS #2029 用の RefreshView を追加
  • AbsoluteLayout を追加 #2136
  • Right-to-Left (RTL) FlowDirectionの追加 #948
  • Button.Icon ImageSourceを追加 #2079

.NET MAUI Preview 7

公式情報:Additional Highlights

  • Xamarin.Forms からアップグレードするプロジェクトをサポートする Effects のサポートの追加 #1574
  • AppThemeBinding の改良による、ダークテーマとライトテーマのモードのサポート #1657
  • ScrollView ハンドラ #1669
  • Android シェルのコアへの移植 #979
  • 複雑なオブジェクトを渡すシェルのナビゲーション #204
  • XAML ホットリロードのためのビジュアルツリーヘルパーの追加 #1845
  • System.ComponentModel.TypeConverterへの切り替え #1725
  • ウィンドウ ライフサイクル イベント #1754
  • ページナビゲーションイベント #1812
  • CSS プレフィックスを -maui に更新 #1877

 
 
以下、随時更新中です。

.NET 6 の Scatter/Gather IO の効果を Visual Studio for Mac 2022 Preview 1 on M1 Mac で試してみましたが、まだ、闇が深かったです(訂正済)

2021/10/05 22:40 検証方法に間違いがあったため(VS for Macデバッグありの実行になっていました)、再度検証し直し記事も訂正しております。ご指摘ありがとうございました。
 
 

はじめに

.NET 6 では FileStream がほぼ完全に書き直されており、速度と信頼性のが高まりました。また、複数のバッファーに対応した(Scatter / Gather IO)新しい API が導入されています。Scatter / Gather IO を使用すると、単一の sys-call で複数のバッファーを渡すことにより、高コストの sys-call の数を減らすことができます。
 
devblogs.microsoft.com
 
 

Visual Studio for Mac 2022 Preview 1 on M1 Mac で試したら...

WindowsLinux でのベンチマーク結果は公式ブログにデータがありましたので、Mac ではどのような結果になるか試してみました。
 
公式ブログの記事内のコードから、サンプルプロジェクトを作成しました。
github.com
 
ベンチマークのライブラリは、BenchmarkDotNet を利用しているようなので、同じように構成しました。
github.com
 
Visual Studio for Mac 2022 Preview 1 で実行した結果ですが...

// * Summary *

BenchmarkDotNet=v0.13.1, OS=macOS Big Sur 11.6 (20G165) [Darwin 20.6.0]
Apple M1 2.40GHz, 1 CPU, 8 logical and 8 physical cores
.NET SDK=6.0.100-rc.1.21463.6
  [Host]     : .NET 6.0.0 (6.0.21.45113), X64 RyuJIT
  DefaultJob : .NET 6.0.0 (6.0.21.45113), X64 RyuJIT


|      Method |     Mean |    Error |   StdDev |
|------------ |----------|----------|----------|
|       Write | 47.92 ms | 1.109 ms | 3.271 ms |
| WriteGather | 48.51 ms | 1.567 ms | 4.621 ms |

 
なんと上記の通り、WriteGather()の方が遅いという結果となりました...
 
 

ベクトル化 IO がうまく機能していない

詳細を解析していないのでなんとも言えないですが、公式ブログでは、Linux ではベクトル化 IO が機能しているとのことでしたが、Mac ではなんらかの理由でうまくベクトル化 IO が機能していない感じです。

一応、.NET 6 と Darwin のソースを調べてみましたが、pwritev() はサポートしているようですが、ベクトル化 IO がうまく機能していない詳細な原因まではわかりませんでした。
 
...と、いったんは思ったのですが、よく見ると、ベンチマーク結果が、X64 となっているので、Rosetta 2 による変換が入っているのが気になります。

ちなみに、意識せず x64 版がインストールされていたのは、dotnet-maui-check でインストールしたからでした。
 
 

Arm64 版 SDK をインストールして再度チャレンジ

というわけで、.NET 6 RC1 SDK をいったん全て削除して、再度 Arm64 版 SDK をインストールして Visual Studio for Mac 2022 Preview 1 で再度試したところ、今度は、無事成功しました。しかも、WriteGather()の方が速く、ベクトル化 IO も効果を発揮しています。

// * Summary *

BenchmarkDotNet=v0.13.1, OS=macOS Big Sur 11.6 (20G165) [Darwin 20.6.0]
Apple M1, 1 CPU, 8 logical and 8 physical cores
.NET SDK=6.0.100-rc.1.21463.6
  [Host]     : .NET 6.0.0 (6.0.21.45113), Arm64 RyuJIT
  DefaultJob : .NET 6.0.0 (6.0.21.45113), Arm64 RyuJIT


|      Method |     Mean |    Error |   StdDev |
|------------ |----------|----------|----------|
|       Write | 45.11 ms | 0.950 ms | 2.772 ms |
| WriteGather | 40.23 ms | 1.304 ms | 3.844 ms |

 
 

今回得た知見

今回の検証で以下のような知見を得ました。

  • M1 Mac .NET 6 の、Scatter/Gather IO は Arm64 版 でしか有効にならない。x64 版では効果がない。
  • M1 Mac .NET 6 SDK の、x64, Arm64 を両方インストールした場合、同じ場所に配置され、後にインストールした方が有効となる。side by side にはならない。
  • M1 Mac .NET 6 SDK の、x64, Arm64 を切り替えたい場合、念のため SDK をいったん削除してから再インストールした方が無難そう。
  • M1 MacVisual Studio for Mac 2022 Preview 1 では Arm64 版 SDK でのデバッグ実行がまだ正常動作しない。x64 版 SDK/Rosetta 2 ならデバッグ実行できる。

 
というわけで、Visual Studio for Mac 2022 の今後のリリースに期待します。
 
 
.NET 6 の更新情報は以下をご覧ください。
hiro128.hatenablog.jp

Visual Studio 2022 for Mac Preview 1 がリリースされましたので状況を確認してみました。

.NET 6 の GA まであと1ヶ月ちょっとのタイミングでようやく、Visual Studio 2022 for Mac Preview 1 がリリースされました。
devblogs.microsoft.com
 

UI が ネイティブの macOS UI で書き直されました。

これが Visual Studio 2022 for Mac の一番大きなトピックです。この件に工数がかかってしまい、他の件は手がまわりきらなかった感があります。見た目の違いは下記の通りです。色味が若干変わっており、視認性が良くなっています。
 
Xamarin の創設者 @migueldeicaza によると、Gtk+ から AppKit に書き直され C# / Xamarin.Mac で開発されているようです。


 

Visual Studio 2022 Visual Studio 2019
f:id:hiro128:20211003155331p:plain f:id:hiro128:20211003155724p:plain

 
その他、クラッシュの軽減とレスポンスが改善しているとのことです。

  • クラッシュの軽減については、長時間使用していないので体感できませんでした。
  • レスポンスの改善については、MacBook Air (M1, 2020) 上で大きな差ではないですが確かにもたつかなくなったという感覚はあります。

 
 

Windows 版に準じた Git の UI が適用されました

自分は、Git の操作はコマンドで行っているので、実際の画面を見てみてもよくわかりませんでしたが、Git のUI が Windows 版に近づいたそうです。確かにコードの変更箇所は見やすくなりました。
 
 

.NET 6 と C#10 への対応

例えば、Visual Studio 2019 for Mac では、.NET 6 RC1 を導入してもエラーが出てしまっていた以下の Minimal API のサンプルが動作するようになりました。
github.com
 

Visual Studio 2022 Visual Studio 2019
f:id:hiro128:20211003163745p:plain f:id:hiro128:20211003163809p:plain

 
 

SDK スタイルの Xamarin プロジェクトはまだ利用できません

下記のように、公式ブログに記載がある通り、SDK スタイルの iOS, Android プロジェクトはサポートされていません。.
 

Visual Studio for Mac continues to support web and cloud development with .NET Core 3.1 and later, mobile dev with Xamarin Traditional projects, and game development using Unity.

 
.NET 6 GA まであと1ヶ月強という状況と後述する MAUI の GA の情報から予想するに .NET 6 GA のタイミングでは、.NET 6 の iOS, Android のワークロードはサポートされず、これまでの非 SDK スタイルの従来の Xamarin.iOS, Xamarin.Android プロジェクトのサポートに留まる可能性が高そうですが、なんとかリリースされることを期待したい思いです。
 
なお、試しに既存の非 SDK スタイルの Xamarin.iOS プロジェクトを開いて、編集、デバッグしてみましたが、問題なく利用できました。
 
したがって、net6.0-android, net6.0-ios といった TFM が利用できるのも、もう少し先になりそうです。
 
 

.NET MAUI の GA は 2022 Q2 に延期されました。

2020年5月の公式ブログでは、以下のように

  • 2020年 Q4 から 2021年 Q3 までプレビュー
  • RC 2021年9月
  • GA 2021年11月

という予定でしたが 2022 Q2 延期になったようです。
devblogs.microsoft.com
 
 

まとめ

Preview 1 の状況をまとめると以下のような状況です。(実際に動作確認した結果です)

ワークロード 対応状況
コンソールアプリ
ASP.NET
Xamarin.iOS
Xamarin.Android
.NET 6 iOS
.NET 6 Android
.NET 6 Mac Catalyst
MAUI

 
まだ Preview 1 ですのでこれから新たな機能がリリースされると思います。次のプレビューを期待して待ちます。

.NET 6 Preview 4 以降で ASP.NET Core プロジェクトを作成するとデフォルトの起動プロファイルが Kestrel になります

.NET 6 Preview 4 以降で ASP.NET Core プロジェクトを作成するとデフォルトの起動プロファイルが Kestrel になります。
devblogs.microsoft.com
 
 
以下のように、デフォルトの起動プロファイルと、プロファイルの並び順に違いがあります。

   .NET 5 (VS2019)       .NET 6 (VS2022 Preview)    
f:id:hiro128:20210928022256p:plain f:id:hiro128:20210928022309p:plain

 
デフォルトの起動プロファイルは、単純に、[AppName].csproj.user の ActiveDebugProfile の値で決まりますので、.NET 5 でも値を修正すれば デフォルトの起動プロファイルが Kestrel になります。

Kestrel の方が軽いですし、クロスプラットフォームなので、既存の .NET 5 のプロジェクトでも デフォルトの起動プロファイルを Kestrel に変更したい場合もあると思います。
 

.NET 5 の例

WebApp2019.csproj.user 初期値(IIS Express デフォルト)
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
  </PropertyGroup>
  <PropertyGroup>
    <ActiveDebugProfile>IIS Express</ActiveDebugProfile>
  </PropertyGroup>
</Project>

 
f:id:hiro128:20210929004743p:plain
 
 

WebApp2019.csproj.user 変更後(Kestrel デフォルト)
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
  </PropertyGroup>
  <PropertyGroup>
    <ActiveDebugProfile>WebApp2019</ActiveDebugProfile>
  </PropertyGroup>
</Project>

 
起動プロファイルが Kestrel に変更されました。
f:id:hiro128:20210929005311p:plain
 
 
 
起動プロファイルの並び順については、[AppName]\Properties\launchSettings.json 内の記載順で決まりますので、こちらも順番を入れ替えれば、 Kestrel, IIS Express, WSL の並び順を自由に入れ替えできます。
 
 

launchSettings.json 初期値(IIS Express が最初に記載されている)
{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:27769",
      "sslPort": 44341
    }
  },
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "swagger",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "WebApp2019": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "swagger",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "dotnetRunMessages": "true",
      "applicationUrl": "https://localhost:5001;http://localhost:5000"
    },
    "WSL": {
      "commandName": "WSL2",
      "launchBrowser": true,
      "launchUrl": "https://localhost:5001/swagger",
      "environmentVariables": {
        "ASPNETCORE_URLS": "https://localhost:5001;http://localhost:5000",
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "distributionName": ""
    }
  }
}

 
JSON の記載順通り IIS Express , WebApp2019(Kestrel) , WSL の順番になります。
f:id:hiro128:20210929005331p:plain
 
 

launchSettings.json 順番入れ替え済み(Kestrel が最初に記載されている)
{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:27769",
      "sslPort": 44341
    }
  },
  "$schema": "http://json.schemastore.org/launchsettings.json",
  "profiles": {
    "WebApp2019": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "swagger",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "dotnetRunMessages": "true",
      "applicationUrl": "https://localhost:5001;http://localhost:5000"
    },
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "swagger",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "WSL": {
      "commandName": "WSL2",
      "launchBrowser": true,
      "launchUrl": "https://localhost:5001/swagger",
      "environmentVariables": {
        "ASPNETCORE_URLS": "https://localhost:5001;http://localhost:5000",
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "distributionName": ""
    }
  }
}

 
こちらも、入れ替えた JSON の記載順通り WebApp2019(Kestrel) , IIS Express , WSL の順番になります。
f:id:hiro128:20210929005347p:plain
 
 
小技ですが、必要になったときに結構忘れたりしますので、備忘録として残しておきました。

Minimal Web API のサンプルコードを作ってみました。

はじめに

Build 2021 のセッション
.NET 6 deep dive; what's new and what's coming | OD485
 
www.youtube.com

 
などで紹介された Minimal Web API について、セッション内でコードの一部は画面で見ることができましたが、公式のサンプルコードの紹介はありませんでした。
 
具体的などのようなコードになるかを確認するために、.NET6 RC1 でサンプルコードを作成しました。
github.com
 
 
.NET 6 の新機能の情報は以下をご覧ください。
hiro128.hatenablog.jp
 
 

プロジェクト

MinimalWebAPISample

Minimal Web API のサンプルです。
f:id:hiro128:20210921234213p:plain
 
Startup.cs も、Controllers も不要で、Program.cs のみで動く
 
Program.cs

using System;
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;

string[] Summaries = new[]
{
    "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

var rng = new Random();

var app = WebApplication.Create(args);
app.MapGet("/", () => "Hello World!");
app.MapGet("/plant", () => new { Name = "cactus" });
app.MapGet("/weatherforecast", () =>
    Enumerable.Range(1, 5).Select(index => new WeatherForecast
    {
        Date = DateTime.Now.AddDays(index),
        TemperatureC = rng.Next(-20, 55),
        Summary = Summaries[rng.Next(Summaries.Length)]
    }).ToArray()
);
await app.RunAsync();

public class WeatherForecast
{
    public DateTime Date { get; set; }
    public int TemperatureC { get; set; }
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
    public string Summary { get; set; }
}

 

MVCWebAPISample

従来からある ASP.NET Core Web API のサンプルです。
f:id:hiro128:20210921234233p:plain
 
長いのでコードは省略しますが、Startup.cs 、Controllers、Program.cs とお作法が多いです。
 
両者は同じ結果を返す API になっていますので、MVCWebAPISample と比べて Minimal Web API でどれだけコードが少なくなるかを確認できます。
 
 

注意点

Minimal Web API のコードは、セッションの内容と .NET6 RC1 SDK を調査した結果から独自に作成したコードですので、正式リリースの .NET6 では動作しなかったり、違うコードになる可能性があります。
 
 

System Requirements

以下の Windows, に対応した Visual Studio 2022 Preview 最新版と .NET 6 SDK RC1 をインストールしてください。Visual Studio 2019 では動作しません。なお、Windows では Visual Studio 2022 PreviewVisual Studio 2019 はサイドバイサイドで動作し、共存可能です。
 

APIのエンドポイント(Minimal Web API, ASP.NET Core Web API 共通)

エンドポイント メソッド レスポンス
/ Get "Hello World!"文字列を固定で返却 f:id:hiro128:20210921235422p:plain
/plant Get レスポンス:植物名(サボテン)のオブジェクト(JSON)を固定で返却 f:id:hiro128:20210921235436p:plain
/weatherforecast Get ランダムな天候を表すオブジェクトのリスト(JSON)を返却 f:id:hiro128:20210921235447p:plain

 
 

まとめ

Minimal Web API のコードは Program.cs ファイルにすべてが記述できており、特に行数が少なくなるようなことはしておりませんが、30行以内に収まっています。
 
ASP.NET Core Web API のコードと比較すると直感的にわかりやすく、簡単な Mock API やシンプルな API を作成するシナリオに利用できそうです。
 

.NET 6 新機能のまとめ(随時更新中)

2021年11月9日から11月11日にかけて、.NET Conf 2021.が開催され、NET 6 もとうとうローンチされました。Preview1 から GA まで段階的に情報や新機能がリリースされており、情報も分散しているため、まとめて確認できる目次がなく不便なので、情報を整理してみました。
  
公式情報も更新されているため、記事は随時更新中です。
なお、各情報の(.NET 6 RC 2)の「.NET 6 RC 2」は、その情報に対する公式の解説があったバージョンを表しています。
  

  

.NETプラットフォームの統合(.NET 6 Preview 4)

.NETプラットフォームの統合は、遡ること2年半、2019年5月6日に Microsoft の公式ブログ「Introducing .NET 5」の中で、「.NET - A unified Platform」としてコンセプトが発表され、2020年11月の .NET 5 のローンチで統合が完了する予定でした。
 
.NET - A unified Platform のコンセプトは以下のとおりです。
・1つのSDK、1つのランタイム、1つのコードベースで、クラウド、ウェブ、デスクトップ、モバイル、ゲーム、IoT、AI、あらゆる種類のアプリケーションを構築できる
・.NETを学んだ後は、同じスキルで上記のすべてのワークロードを構築できるようになる
 
ですが、残念ながら 2020年の .NET 5 では、Xamarin の一部である AndroidiOS、および macOS の 機能の統合は間に合わず、.NET 6 での統合と延期されました。今回、.NET 6 では、.NET 5 で先送りになった、Xamarin の一部である AndroidiOS、および macOS の 機能の統合が完了する予定でしたが、残念ながら Xamarin の統合はまた延期となりました。ただし、今回は Preview として利用可能(※1)になっており、完全な統合まであと少しとなっています。(それまでは、従来の Xamarin が更新され続け、本番用のモバイルアプリの構築には Xamarin が推奨となります。)
 
具体的には、.NET MAUI(※2) のローンチが 2022年第2四半期の初めを目標に延期されたことにより、.NET 6 の iOSAndroidmacOS、MacCatalyst の各ワークロードの GA も 2022年第2四半期の初めへ延期となっています。
 
あと半年程度で、ついに .NET におけるプラットフォームの統合が完了し、.NET - A unified Platform が実現します。
 
なお、Preview ではすでに、Xamarin.Android、Xamarin.iOS の名称ではなく、Microsoft.iOSMicrosoft.Android が使用されています。

f:id:hiro128:20211114163012p:plain f:id:hiro128:20211114162929p:plain

 
(※1)Preview として、Windows 版の Visual Studio 2022 から .NET MAUI が利用可能です。(Visual Studio 2022 for Mac はまだ未対応)
Visual Studio 2022 for Mac でも iosandroid-aot のワークロード(Microsoft.iOSMicrosoft.Android)が Preview で利用できます
 
(※2).NET MAUI は、.NET Multi-platform App UI の略称です。Xamarin.Formsの後継の AndroidiOSmacOS、および Windows 用の .NET を使用してネイティブクロスプラットフォームアプリを構築するためのマルチプラットフォームアプリ UI です。
 
公式情報:
devblogs.microsoft.com
docs.microsoft.com
 
 

サポート

.NET 6 は2021年11月8日にリリースされ、LTSリリースとして3年間サポートされます(2024年11月8日まで)。

Version リリース日 リリースタイプ サポート期限
.NET 6 2021/11/8 LTS 2024/11/8
.NET 5 2020/11/10 Current 2022/5/8
.NET Core 3.1 2019/12/3 LTS 2022/12/3

 
.NET 6 は .NET Framework と .NET Core が統合されてから最初の LTS リリースです。.NET Framework からの移行をどうすべきかについても気になることでしょう。(移行すべきかどうかの考え方については後述します)
 
サポートに関する詳細は以下をご覧ください。
github.com
  

対応プラットフォーム

動作プラットフォームは以下のとおりです。

Windows x86, x64, Arm64(クライアントのみ)
Linux x64, Arm32, Arm64
Android x64, Arm32, Arm64
iOS x64(シミュレータ), Arm32, Arm64
Mac x64, Arm64

  
詳細は以下をご覧ください。
github.com
 
 

.NET 6 のターゲットフレームワークモニカ(TFM)

新しいプラットフォームのサポートの追加で、TFM が追加されています。TFM は csproj ファイルの TargetFramework セクションに記載します。TFM とは「ターゲットフレームワークの呼称」という意味で、アプリまたはライブラリで使用できるようにする API のセットを表すものです。

以下のように .csproj ファイル内で定義します。

<TargetFramework>net6.0</TargetFramework>


.NET 6 にはOS固有のバインディングを含む以下の TFM があります。.NET Framework 時代には、TFM から利用できる API が直感的にわからず非常に難解でしたが、ベースの TFM (net6.0)と OS 固有のフレーバー(windowsAndroidios など)によって構成されるよう整理され、とてもわかりやすくなりました。

devblogs.microsoft.com
  

SDKワークロード(.NET 6 RC 1)

TFMが、主要な機能とオプションの組み合わせで表現されることに合わせて、SDK 自体も主要な機能と各ワークロードのオプションに分割されています。.NET 6 では新たに追加された、.NET MAUI、AndroidiOS、WebAssembly が別のワークロードとして用意されています。これは、これまでのような、すべての機能を含むモノリシック SDK では、ビルド時間が長くなり、配布サイズも大きくなってしまうからです。
  
詳細は以下をご覧ください。
devblogs.microsoft.com

  
dotnet workload list コマンドを実行すると、以下のようにインストールされているすべてのワークロードが一覧表示されます。
docs.microsoft.com
 

Installed Workload Ids
----------------------
android-aot
ios
maccatalyst
macos
maui
tvos
wasm-tools

 
.NET 7 では、ASP.NETWindows デスクトップなどのコンポーネントもオプションにする予定となっています。(例えば net7.0-aspnet のようなワークロードが追加されるということになると予想されます。)
 
 

.NET 6 のハイライト

.NET 6 のハイライトは、基本的に以下の 4 つに集約されます。

  1. パフォーマンスの向上
  2. 開発の生産性の向上
  3. セキュリティ対策の向上
  4. macOS、Arm64関連 の対応

 

パフォーマンスの向上

.NET 6 ではランタイムに対する多数のパフォーマンス改善が行われています。ライブラリ開発者の方にとっては詳細を理解することがとても有効ですが、アプリ開発者の場合、.NET6 をターゲットフレームワークにすれば自動的にパフォーマンスが改善するものもあるため、移行するだけでもある程度のメリットを享受できます。
 
公開されているベンチマークで Node.js よりも10倍速い、また、Entity Framework Core のパフォーマンスは .NET 5 と比べて最大92%の速度向上を実現しているなどのパフォーマンス向上を実現しており、既存の .NET Web アプリケーションを .NET 6 にマイグレーションすることで速度の向上を見込めます。
 
.NET でパフォーマンスの向上に注力する最大の理由は、「クラウドコンピューティングのコスト削減」です。少ないコンピューティングリソースで必要なパフォーマンスを実現できることで、クラウドのコストを最適化できます。
 
以下、具体的なパフォーマンスを改善の例のいくつかを簡単にご紹介します。
 

JIT(ジャストインタイムコンパイラ)の改善

「インライン化による最適化」は、コンパイラがメソッドの呼び出し先からコードを取得し、それを呼び出し元に直接出力するプロセスです。これにより、メソッド呼び出しのオーバーヘッドが回避されます。さらに呼び出し先のコードが結果として定数を返すような場合、コンパイル時に計算を済ませてしまい、呼び出し元のコンテキストに公開することで、メソッド呼び出しを操作全体を定数に変換できます。

ただし、インライン化を行うとすべての呼び出し元に呼び出し先の結果のコードがコピーされるため、内容的には同じコードだとしても、CPUから見れば別のコードと扱われるため、CPUのキャッシュメモリ上で多くのエビクション(キャッシュメモリからの削除)とロードが強制されてしまい、かえって速度が低下してしまう場合もあります。それを最適化するために、コンパイラがインライン化するかどうかの判断を厳密に行うように改善し、パフォーマンスを向上させています。

公式情報:Performance Improvements in .NET 6
devblogs.microsoft.com
  

IOの改善

FileStream の実装はとても古くパフォーマンスに関連する多くの問題がありましたが、ほとんど手付かずのままでした。.NET 6 では FileStream がほぼ完全に書き直されており、速度と信頼性が高まりました。また、複数のバッファーに対応した(Scatter / Gather IO)新しい API が導入されています。Scatter / Gather IO を使用すると、単一の sys-call で複数のバッファーを渡すことにより、高コストの sys-call の数を減らすことができます。
 
Scatter / Gather IO は「ベクトル化 I/O」とも呼ばれ、単一の sys-call が複数のバッファからデータを順次読み込んで単一のデータストリームに書き込む、またはデータストリームからデータを読み込んでバッファのベクトルで定義された複数のバッファに書き込む入出力方式です。
 
関連記事 
hiro128.hatenablog.jp
 
公式情報:
devblogs.microsoft.com
 
 

ディクショナリーの値が構造体の場合の処理の高速化(.NET 6 Preview 3)

新しい unsafeな API - CollectionsMarshal.GetValueRefOrNullRef - が追加され、ディクショナリー内の構造体の値をより速く更新できるようになりました。
なお、この新しいAPIは、一般的な用途ではなく、高性能なシナリオを想定しています。

このAPIは、構造体の値への参照を返しその場で更新することができます。これまでは、構造体の辞書値の更新には、辞書の検索と構造体のスタックへのコピーが必要で、高性能なシナリオではコストの問題がありました。今回の改良では、キーのハッシュ化を2回から1回に減らし、構造体のコピー操作をすべて削除できました。

なお、GetValueRefOrNullRef を利用する場合、Unsafe.IsNullRef(ref value) を使用して null 参照の確認が必要です。

この API 追加のバックグラウンドをご説明します。
変更可能な構造体を利用する場合、誤って構造体をコピーしてしまい、元の構造体とコピー先の構造体の値が異なるものになってしまうトラブルが発生しがちです。

これを防ぐには「構造体をコピーした上で値を変更し結果を元の場所にコピーして戻す」必要があります。これは小さな構造体なら問題ありませんが、構造体が大きい場合、高コストになり問題です。そもそもパフォーマンス向上のために変更可能な構造体を使用する場合が多いので、いったんコピーし変更の上、再度元の場所にコピーし直すというのは本末転倒です。

なお、NET 5 以降なら、List<T> に対しては、CollectionsMarshal.AsSpanメソッドでコレクションの Span ビュー(ref 構造体)を取得できます。

同じようにディクショナリーでも ref 構造体を取得できるようにするため、CollectionMarshal.GetValueRefOrNullRef という新しい API が提供されました。なお、実はこの機能は internal メソッドDictionary<TKey, TValue>.FindValue として既に存在しており、.NET 6 で GetValueRefOrNullRef メソッドとして公開されました。

github.com
公式情報:
Faster handling of structs as Dictionary values
CollectionsMarshal.GetValueRefOrNullRef<TKey,TValue>(Dictionary<TKey,TValue>, TKey) メソッド
 
 

開発の生産性の向上

開発の生産性の向上のために .NET インナーループのパフォーマンス向上に注力しています。「インナーループ」とは、コードの変更、ビルド、テストなどで繰り返し使用するプロセスのことです。
 
インナーループの一部として頻繁に使用するツールやワークフローを最適化することで、ビルド時間の短縮、デバッグ時の手順の簡略化、実行中アプリの変更のライブ反映(Hot Reload )など、開発中の細かい待ち時間が短縮され、コーディングの時間を増えることで生産性が最大限に高められます。
 
Windows Form アプリ、WPF アプリ、Web アプリ、MAUI アプリ(予定)が Hot Reload に対応しています。
 
インナーループの改善では、定常状態のパフォーマンスではなく、ランタイム、アプリモデル、dotnet CLIMSBuild などの起動時のパフォーマンスや、ツールのエンドツーエンドのパフォーマンスに焦点を当てています。最適化したいアプリケーションの関連領域をプロファイリングし、得られたデータを分析して影響が大きい原因やボトルネックを探し、それに対する修正策を考え、さらに次の影響力のある項目を見つけるためにプロセスを繰り返して改善を進めています。
結果として new、build、run などの dotnet コマンドを中心に、開発者のインナーループに関わる主要な部分のオーバーヘッドを削減することに成功しています。
 

 
公式情報:Theme — Improve .NET Inner Loop Performance
 
 

セキュリティ対策の向上(.NET 6 RC 1)

2021年の初頭に、.NET ランタイムのセキュリティ対策のロードマップが発表されています。

これらのセキュリティ対策は単なるセキュリティパッチではなく、ランタイムの構造に手を入れる根本的な対策を含んでおり、それらは .NET 6 以降にのみ実装されます。.NET Framework のセキュリティパッチでは実装されません。
github.com
なお、.NET 6 RC 1 では、以下の2つの重要なセキュリティ対策がプレビューとなりました。なお、.NET 7ではこれらはデフォルトで有効になる予定です。
 

Hardware-enforced Stack Protection(ハードウェア強制型スタック保護)

ハードウェア強制型スタック保護は、Intel の第11世代 Tiger Lake プロセッサに および、AMD Zen 3 プロセッサに Control-flowEnforcement Technology (CET)として搭載されているセキュリティ機能です。

x64 CPU のハードウェアに依存した機能ですので当然ながら、x64 プラットフォームでのみ有効にできる機能となります。

CET はシャドウスタック(コールスタックの「影(シャドウ)」となる第2の別のスタック)を使ってすべてのリターンアドレスを記録しておく技術です。x64 のアセンブリ言語で、CALL 命令ごとにリターンアドレスがコールスタックとシャドースタックの両方にプッシュされ、RET 命令ではコールスタックとシャドースタックの両方からリターンアドレスをロードします。

2つのアドレスが一致しない場合、プロセッサは制御保護例外(#CP—Control-Protection Exception)を発行します。これがカーネルにトラップされ、セキュリティを保証するためにプロセスを終了させます。

シャドウスタックはリターンアドレスのみを格納するため、追加のメモリオーバーヘッドを最小限に抑えることができます。
 
公式情報:
CET
Understanding Hardware-enforced Stack Protection
.NET 6 compatibility with Intel CET shadow stacks (early preview on Windows) 
 
 

W^X(write xor execute:書き込みと実行の排他)

W^X は、プロセスやカーネルアドレス空間内のすべてのページが、書き込み可能か実行可能かのいずれかであり、両方はできないというメモリ保護ポリシーです。この保護機能がないと、プログラムはデータ用のメモリ領域にCPU命令を書き込み(データ「W」として)、その命令を実行(実行可能「X」、または読み取り-実行「RX」として)することができてしまいます。

W^X は、最も単純な攻撃経路を遮断します。この機能がない場合、その他のより高度な対策はバイパスされる可能性があるため、その他の対策の意味がない結果となってしまいます。W^X を導入したことで前提条件がそろったため、今後 CET のような他の補完的な対策を追加される予定となっています。

Apple は「macOS」の将来のバージョンで W^X を必須としました。W^X は、.NET 6 を搭載したすべての OS で利用可能ですが、デフォルトで有効なのは、Apple Silicon 上で動く macOS のみです。.NET 7 ではすべての OS で有効になります

公式情報:W^X
 
 

macOS Arm64 および Windows Arm64 に関するアップデート

Windows .NET では最近 Arm64 関連のサポートが強化されていますが、これは見逃せない動きです。Arm64 ブラットフォームは x64 プラットフォームに比べ電力効率で大幅に優れています。 クライアントマシン 1 台レベルでは、消費電力の差はたかが知れていますが、クラウドのデータセンターの規模になるとその差は膨大になります。Arm64 のサポートが今後進めば、クラウドでも Arm64 の利用がどんどん進むことでしょう。x86 と併用される場合でも、同じ性能であれば Arm64 の方が料金が安くなる可能性が高いと予想しています。将来を見据え、場合によっては x86 から Arm64 に移行できる準備も進めておくためにも、Arm64 の動向はウオッチしておいた方が良いでしょう。
 

SDK / ランタイム関連(.NET 6 RC 2)

.NET 6 RC2 以降 では、x64 および Arm64 .NET インストーラーがサイドバイサイドでインストールされるようになり(x64 と Arm64 のビルドが別々の場所にインストールされます)x64 と Arm64 の共存を実現しています。(これまでは、x64 と Arm64 のビルドがお互いに上書きされてしまっていました)

 
macOSWindows の Arm64 マシンで、.NET 6 RC2 以降を利用するには、Arm64 と x64 の .NET 6 と 以前の .NET(.NET 5 / .NET Core 3.1 など)のすべての .NET SDKとランタイムを一旦アンインストールして再インストールをする必要があります。なお、再インストール時に利用する以前のバージョンの .NET(.NET 5 / .NET Core 3.1 など)の .NET SDKとランタイムは今後提供する予定です。
 
SDKは、Arm64 では .NET 6 以降のみをサポートします。それ以前のSDKによるビルドはArm64ではブロックされます。ランタイムは、Arm64 および x64 のすべてのサポート中のバージョンがサポートされます。

.NET 6 RC2 以降では、(x64エミュレーションを含む)Arm64 向けの最終的な .NET 6 エクスペリエンスの大部分が提供されています。
 
Windows Arm64 用の .NET 5 SDK は、.NET 6 RTM に合わせて早期にサポートを終了します。
 
Arm64 アーキテクチャ上では、ネイティブ・アーキテクチャのパフォーマンスの享受、1つの SDK を管理すればよいなど、よりより良い体験ができるため Arm64 SDKの利用を推奨します。
 
なお、.NET Framework でも、「.NET Framework 4.8.1」で Arm64 のサポートが追加されます。


公式情報:macOS and Windows Arm64 Update
 

macOS ユニバーサルバイナリー(.NET 6 Preview 1)
  • .NET 6 では、ワークフローで .NET アプリのユニバーサルバイナリーを公開することはできない
  • この機能の必要性を .NET 7 で再検討する。
  • 現在、macOS 向けとしては Intel 専用のバイナリーしかビルドきない。ユニバーサルバイナリーではない Apple Silicon 専用のバイナリーもビルドできない。
  • ビルドした Intel 専用のバイナリーを Rosetta 2 を介して Apple M1 上で動作させることはできる。

公式情報:Native Apple Silicon
 
 

.NET 6 に移行すべきか .NET Framework 4.8 にとどまるべきか

状況が許すのであれば、 .NET 6 に移行することを推奨します。.NET 6 で移行を見送る場合でも、次の LTS である 2023 年の .NET 8 リリースをターゲットに移行を進めるように進めることをお勧めします。
移行にあたり、.NET アップグレード アシスタントを利用すると、SDKスタイルの .csproj への移行、TFM(TFMについては後述します)のアップデート、NuGet パッケージの更新、テンプレートファイルや config ファイルの追加などの定型的な移行についてのガイドが表示され、ステップ・バイ・ステップで自動的に移行を進めることができるので、移行作業の負荷が下がります。ただし、移行を完全に完了するためにさらに手作業での修正が必要です。
 
なお、.NET アップグレード アシスタントで以下の種類の .NET Framework アプリの移行がサポートされています。

 
そして、.NET Framework アプリを .NET 6+ への移行をお勧めする最大の理由はセキュリティです。
 

パッチではない新たなセキュリティ対策は .NET 6 以降にのみ実装される

上記、セキュリティ対策のセクションで述べたように、すでに .NET 6 にセキュリティ対策関連や HTTP/3 など新たな注目すべき機能が実装され始めており、 2年後の .NET 8(次のLTS) リリース時にはかなりの機能の差が拡大すると見込まれます。そして、これらの新機能は .NET Framework 4.8 では提供されません。

特にセキュリティ対策関連については、今後のロードマップが示されていますが、これらのセキュリティ対策は単なるセキュリティパッチではなく、CPU の新機能やランタイムの構造に手を入れる根本的な対策を含んでおり、それらは .NET 6 以降にのみ実装されます。
したがって、.NET 8 の世代では、 .NET Framework 4.8 はまだサポート期間内なので動作はするものの、セキュリティ対策の観点からはあくまでもパッチの提供にとどまり、新機能による根本的な対策は行われず、世代的に陳腐化したものとなってしまうと考えられます。
 
これらを加味した、移行の指針を以下に示します。
  

新規アプリなら .NET 6 を選択

いまだに、.NET 6 を「枯れていない」ということから避ける意見も見受けられますが、.NET Core の系統も、.NET 6 で 5 世代目であり充分「枯れて」います。もはや新規アプリ開発のリスクは .NET Framework 4.8 と差はないと考えて問題ありません。このタイミングで .NET 6 を「枯れていない」として避けることは、逆に「ではいつになれば、枯れていると判断できるのか」という理由付けが必要な状況になってしまうでしょう。
 

既存アプリもなるべく.NET 6 に移行

問題になるとしたら、既存アプリ移行のシナリオでサードパーティー製のライブラリが .NET 6 に対応していない、開発元がすでに存在しないというようなケースです。この場合、代替のライブラリを探したり、同等機能をスクラッチ開発しなければならないなどリスクはあります。ですが、サードパーティー製の .NET Framework 対応のライブラリの保守も継続はされるでしょうが、もはやあくまでも延命措置としての保守であり、今後サポートの優先度を下げられてしまうリスクも考慮すると、.NET 6 へ移行するのが賢明です。
 

.NET Framework 4.8 のまま継続した方が良いケース

例えば、当該アプリを動かす環境が一切パブリックネットワークに接続しておらず完全に閉域で使用されるアプリであれば、そのまま .セキュリティ面のリスクも少ないため、ギリギリまで .NET Framework 4.8 のまま維持しそのまま終息させてしまう選択は有効です。
 
 
よって、かなり限定されたケース以外では超えなければいけないハードルはあるにせよ、このタイミングで移行を開始し2年後の .NET 8 リリース時には移行完了するようなスケジュールを検討するのはとても良い選択と考えられます。
 
 

API の追加

FileStreamを使用しない、ファイルの読み取りと書き込み

.NET 6には、FileStreamを使用せずにファイルの読み取りと書き込みを可能にする新しい低レベルAPIが追加されています。
devblogs.microsoft.com

 

C# 10 の更新情報

C# 10 の新機能については以下の記事にまとめられています。
docs.microsoft.com
 

レコード構造体

  • C# 9 のクラスベースのレコードと似ているが、いくつかの重要な違いがある。
  • レコード構造体では、初期化専用のプロパティが許可されている
  • 初期化後に init キーワードが設定されているプロパティを再割り当てしようとすると、コンパイルエラーが発生する
  • レコード構造体はレコード クラスに取って代わるものではなく、レコード クラスからレコード構造体への移行を推奨するものではない
  • クラスと構造体のどちらのレコードを使用するかは、使用する前に選択する必要がある。

公式情報:
Record structs
レコード (C# リファレンス)
 

global using ディレクティブ

  • すべてのソースファイルで使用したい名前空間を、各ソースファイルで宣言されているかのように指定することができる。
  • using staticやaliasingと一緒に使うことができる
  • 共通の using 宣言を使用できるようになり、多くの using 行が不要になる。
  • この機能はPlatform名前空間に最も適しているが、どの名前空間にも使用することができる。
global using System;
global using static System.Console;
global using E = System.Environment;

公式情報:
Global usings
 

暗黙的な using ディレクティブ

参考情報:SDK ごとに追加される暗黙の using ステートメント

  • 既存のプロジェクトを .NET 6 以降に再ターゲットするときに、暗黙的な global using ディレクティブは追加されないので注意(コンパイルできなくなる)
  • 手動で、ImplicitUsings MSBuild プロパティ を true または enable に設定することで、C# プロジェクトでこの機能を有効にすることができる
  • この機能を無効にすると、例えば、System 名前空間が宣言されなくなるため、アプリがコンパイルされなくなるというような事象が発生する

公式情報:
Implicit usings
.NET SDK プロジェクトの MSBuild リファレンス - ImplicitUsings プロパティ
 

ファイルスコープの名前空間宣言

  • インデントや行数を減らすことを目的とした機能。
  • 従来の3行の構文は入れ子にすることができる。
  • 新しい1行の構文は入れ子にすることができない。
  • ファイルスコープ付き名前空間宣言は、1つのファイルにつき1つだけ使用できる。3行構文と同様に、ファイル内で定義されたすべての型の前に宣言する必要がある。
  • 名前空間宣言は、最上位レベルのステートメントと互換性がない。最上位レベルのステートメントは、最上位レベルの名前空間内に存在する。
  • 例えば、partial class 構文を使用して Program クラスにメソッドを追加する場合、partial class の Program クラスも最上位の名前空間に存在する必要がある。

新しい1行の構文

namespace Foo;

従来の3行の構文

namespace Foo
{
}

公式情報:
File-scoped namespace declaration
File Scoped Namespaces
参考情報:
新しい C# テンプレートで、最上位レベルのステートメントが生成される
 
 

ラムダ式の自然型

  • ラムダ式に対して Func<...>Action<...> などのデリゲート型を強制的に宣言するのではなく、コンパイラにより、パラメーターと式の型からデリゲート型を推論する。
  • ラムダ式が自然型の場合、System.Object、System.Delegate などの弱い型に割り当てることができる。
  • 明示的なデリゲート型なしでラムダとメソッドグループを使用できるシナリオが増える。
var parse = (string s) => int.Parse(s);

上記の場合、コンパイラにより、parseFunc<string, int> と推論することができます。上記のように当てはまる Func または Action が存在する場合、コンパイラには Func または Action のデリゲートが使われます。 それ以外の場合、デリゲート型が合成されます。 たとえば、ラムダ式のパラメーターが ref の場合や、パラメータの数が多い場合などは型コンパイラによって、型が合成されます。 ラムダ式が自然型の場合、System.Object、System.Delegate などの弱い型に割り当てることができます。

わかりやすい例として、この機能は ASP.NET の Minimal API のシナリオで便利です。
.NET 6 では以下のオーバーロードが MapGet 拡張メソッドに追加されています。(Delegate handler パラメータに注目してください。)

public static Microsoft.AspNetCore.Builder.RouteHandlerBuilder MapGet (this Microsoft.AspNetCore.Routing.IEndpointRouteBuilder endpoints, string pattern, Delegate handler);

MapGet(IEndpointRouteBuilder, String, Delegate)

上記のように、MapGet メソッドで Microsoft.AspNetCore.Http.RequestDelegate ではなく、Delegate を利用できるようになったため、下記のコードのように、明示的なデリゲート型なしでラムダを記述できるようになりコードがスッキリしました。

using System;
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;

var app = WebApplication.Create(args);
app.MapGet("/", () => "Hello World!");
app.MapGet("/plant", () => new { Name = "cactus" });
await app.RunAsync();

 
公式情報:
Natural types for lambdas
ラムダ式の自然型

Minimal API については以下を参照ください。
参考情報:
hiro128.hatenablog.jp
 
 

const および文字列補間

  • プレースホルダーの値も定数であることを条件に、constで文字列補間を使用できるようになった。
  • C# コンパイラは、補間された文字列のすべての部分が文字列リテラルであることを認識し、あたかも 1 つの文字列リテラルとして書かれたかのように IL に出力することができる。
  • これによってパフォーマンスがアップする場合がある。
const string Greeting = "Hello";
const string Name = ".NET 6";
string result = $"{Greeting}, {Name}!";

上記のように補間された文字列のすべての部分が文字列リテラルであることを認識できる場合、C#コンパイラは、単一の文字列リテラルとして記述されているかのように、これをILに出力できる。

string result = "Hello, .NET 6!";

公式情報:
const and interpolated strings
String Interpolation in C# 10 and .NET 6
 
 

拡張プロパティ パターン

  • ネストされたプロパティまたはプロパティ パターン内のフィールドを参照できる

以下の C# 9.0 のコードは、C# 10.0 では簡潔に記述できます。

C# 9.0

public record Point(int X, int Y);
public record Segment(Point Start, Point End);

static bool IsAnyEndOnXAxis(Segment segment) => segment is { Start: { Y: 0 } } or { End: { Y: 0 } };

 
C# 10.0

public record Point(int X, int Y);
public record Segment(Point Start, Point End);

static bool IsAnyEndOnXAxis(Segment segment) => segment is { Start.Y: 0 } or { End.Y: 0 };

公式情報:
Extended property patterns
プロパティ パターン
 
 

C#プロジェクトテンプレートのモダナイズ(.NET 6 RC 2)

新しいテンプレートでは、以下のような言語機能が使われています。
これらの機能に共通するテーマは、コードエディタでコードを見るときのノイズ(例えば、お作法的な記述)を減らし、より重要な側面を表すシグナルを増やすことです。
公式情報:
.NET SDK: C# project templates modernized
破壊的変更: テンプレートの C# コードが以前のバージョンでサポートされない
 

 

コンソールアプリテンプレート(.NET 6 RC 2)

コンソールアプリのテンプレートは、.NET 5 のものと比べはるかに最小限ですが、機能の低下はありません。

Program.cs はたったこれだけになります。
using System; も namespace も Program クラスも Main メソッドも記述しません。

// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");

また、暗黙的な using ディレクティブがオプトイン機能となり(ImplicitUsings)、テンプレートで有効になっています。

csproj ファイル

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>

公式情報:Console template
 

Web アプリテンプレート(.NET 6 RC 2)

  • Web アプリのテンプレートも同様に最小限のものとなった。
  • Program.cs のみが必要で、Startup.cs が不要になった。

公式情報:Web templates
 

Windows Forms アプリテンプレート

  • 1行の構文のファイルスコープ付き名前空間宣言を使用するようになった
  • 暗黙的な using ディレクティブが有効になった

公式情報:Windows Forms templates
 
 

ライブラリー:ネイティブメモリのAPI(.NET 6 Preview 7)

  • System.Runtime.InteropServices.NativeMemory.NativeMemory を介して公開される新しいネイティブメモリー割り当てAPIが追加された
  • アプリケーション開発者向けではない
  • ライブラリ開発者がパフォーマンスをチューニングしたい時などに利用する想定

API の詳細:NativeMemory クラス

公式情報:
Libraries: NativeMemory APIs

 
 

ASP.NET Core のアップデート

.NET 6 の ASP.NET Core のアップデートについては以下の記事を参照ください。
hiro128.hatenablog.jp
 
 

.NET MAUI のアップデート

.NET MAUI のアップデートについては以下の記事を参照ください。
hiro128.hatenablog.jp
 
 
以下、随時更新中です。