.NET Aspireを試してみた

# 概要
.NET Confで紹介されていた.NET Aspireを実際に触ってみた記録です

## 準備
### Visual Studio
Preview版をインストールします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7886/f3a6df5d-9307-3006-ab18-e36cf4164510.png)

#### Preview版

1. ヘルプ→更新プログラムの確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7886/97a64a01-6db2-68d9-526c-9b01dff8c1a8.png)

2. 更新プログラムの設定を変更する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7886/1197ca05-65ab-2411-8305-835fa11e4056.png)

3. 更新チャネルを「Preview」に変更する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7886/aa00f60f-173a-1eaa-bbc3-7dae7ed792f9.png)

4. コンポーネントを追加する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7886/2dea6ad8-6c96-b4b5-ba06-377be7cc98b6.png)

## プロジェクト作成

まずは「ASP.NET Core Webアプリ」を「AspireTests.Web」という名前で新規追加します。

デモでは、プロジェクト作成の際の「.NET Aspire オーケストレーションへの参加」をオフにしてスタートしていたので、ここではオンにしてスタートしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7886/28a33dd8-1536-a779-1b50-9be68e13a861.png)

### 初期状態
Aspireプロジェクトが自動で追加されていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7886/0b9df562-af94-cf59-e5b1-0bba92776549.png)

そのままデバッグ実行するとAspireの管理画面が立ち上がります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7886/d66ac68b-448f-39a7-5745-b0d5ef78ed57.png)

素晴らしい。

### APIプロジェクト追加
「ASP.NET Core Web API」を「AspireTests.API」という名前で追加し、Webから呼ぶように変更します。

こちらでも「.NET Aspire オーケストレーションへの参加」をオンにしてスタートします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7886/861f7502-65ab-0229-c02a-b69b068ed32a.png)

とりあえず、どちらのプロジェクトも起動できているようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7886/dc541640-3deb-eacf-2f22-dc624551a227.png)

素晴らしい。

### WebとAPIの連携
Web側からAPIを呼ぶ変更を加えてみます。

#### APIから取得したデータをテーブル表示する
```cs:Index.cshtml
@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>
<!--以下追加-->
<div>
    <table>
        <thead>
            <tr>
                <th>date</th>
                <th>temperatureC</th>
                <th>temperatureF</th>
                <th>summary</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var weatherForecast in Model.Forecasts)
            {
                <tr>
                    <td>@weatherForecast.Date.ToShortDateString()</td>
                    <td>@weatherForecast.TemperatureC</td>
                    <td>@weatherForecast.TemperatureF</td>
                    <td>@weatherForecast.Summary</td>
                </tr>
            }
    </table>
</div>
```

#### APIからJSONデータを受け取り、モデルとしてIndex.cshtmlへ受渡しする

```cs:Index.cshtml.cs
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace AspireTests.Web.Pages;

public class IndexModel : PageModel
{
    private readonly ILogger<IndexModel> _logger;

    public IndexModel(ILogger<IndexModel> logger)
    {
        _logger = logger;
    }

    public void OnGet()
    {
        HttpResponseMessage response = new HttpClient().GetAsync("http://localhost:5096/WeatherForecast").Result;
        Forecasts = response?.Content?.ReadFromJsonAsync<List<WeatherForecast>>().Result ?? new();
    }

    internal List<WeatherForecast> Forecasts { get; set; } = new();
    internal 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; }
    }
}
```

#### AspireTests.AppHost > Program.csを変更する

Webを動かすためにはAPIが動いていないとダメですが、Webを先に追加した都合上、起動順序が逆になっています。どちらも起動するので実運用上はほとんど問題ないはずですが、一応直しておきます。

```cs:Program.cs
var builder = DistributedApplication.CreateBuilder(args);
//APIを先に起動する
builder.AddProject<Projects.AspireTests_API>("aspiretests.api");

builder.AddProject<Projects.AspireTests_Web>("aspiretests.web");

builder.Build().Run();
```

なお、```"aspiretests.api"```の部分はAspireで表示されるだけの文字列であるため、変更可能。

### 起動結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7886/0e58e667-76d7-5081-9043-0fc7df1d9408.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7886/bf69167e-210c-33b6-5cda-4e73356e1387.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7886/36a19aa9-c707-6be0-8381-1a30c4b0e366.png)

とりあえず上手くいった模様。
素晴らしい。

## ログの確認
APIにDIされている_loggerを使ってログを出力し、Aspire上から確認してみます。

### ログの出力

データ返却しているところにログを仕込んでみます。
少し分かりやすいよう生成するデータを5から50に変更しました。
```cs:WeatherforecastController.cs
    [HttpGet(Name = "GetWeatherForecast")]
    public IEnumerable<WeatherForecast> Get()
    {
        _logger.LogInformation("GetWeatherForecast: called");
        var data = Enumerable.Range(1, 50).Select(index => new WeatherForecast
        {
            Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = Summaries[Random.Shared.Next(Summaries.Length)]
        })
        .ToArray();
        _logger.LogInformation($"GetWeatherForecast: data created");
        return data;
    }
```

### ログの確認方法

1. Traces→View
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7886/3b3b24fe-c791-0036-38ab-80e5d3b4d66a.png)

1. aspiretests.apiをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7886/fcded1a7-c49c-1353-e6f1-098471f7c5e6.png)

1. View Logsをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7886/9fdc4e6a-f280-8f7e-5ecc-862649d004fe.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7886/948a8873-3b1a-e4a8-14ed-086d69c96ae6.png)

50件を作成するのに4msかかっている模様、とか、printfデバッグはここからでもできるよ、と。

# 所感

とりあえず起動したまでなので、まだ便利さを感じ取れてはいない。が、ログが見やすくなっていたり、起動順序などをプログラムで表現できたりと、しっかり使えれば便利になりそうな予感がする。