前回はこちら
前回からの続き
後輩: 先輩、Angular にも DI の仕組みがあるんですね!バックエンドの ASP.NET Core とどう連携するのか、具体的なコードが見てみたいです。
先輩: 了解!じゃあ、ASP.NET Core のバックエンドでコーヒー豆の在庫を取得するサービスと、それを Angular のフロントエンドで利用する例を見てみよう。
ASP.NET Core (C#) - バックエンド
先輩: まずは ASP.NET Core のバックエンド。コーヒー豆の在庫管理を行うサービスインターフェースと、その実装クラスを定義するよ。
public interface ICoffeeRepository
{
Task<int> GetStockAsync(string coffeeName);
}
public class SqlServerCoffeeRepository : ICoffeeRepository
{
private readonly string _connectionString;
public SqlServerCoffeeRepository(string connectionString)
{
_connectionString = connectionString;
}
public async Task<int> GetStockAsync(string coffeeName)
{
// ここでデータベースにアクセスして在庫を取得する処理を実装
Console.WriteLine($"SQL Serverから{coffeeName}の在庫を取得します...");
await Task.Delay(500); // 模擬的な遅延
return new Random().Next(0, 100); // 実際にはDBから取得
}
}
先輩: そして、このリポジトリサービスを DI コンテナに登録するんだ。Program.cs で以下のように設定する。
var builder = WebApplication.CreateBuilder(args);
// ... 他のサービス登録 ...
// わかりやすく書いてるだけで、実際には AddDbContextPool などを使います
builder.Services.AddScoped<ICoffeeRepository, SqlServerCoffeeRepository>(provider =>
{
var configuration = provider.GetRequiredService<IConfiguration>();
var connectionString = configuration.GetConnectionString("CoffeeDatabase");
return new SqlServerCoffeeRepository(connectionString);
});
// ...
先輩: これで、ASP.NET Core のコントローラーなどから ICoffeeRepository をコンストラクタインジェクションで利用できるようになった。
Angular (TypeScript) - フロントエンド
先輩: 次に Angular のフロントエンド。バックエンドの API から在庫情報を取得するサービスを定義するよ。
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
interface StockResponse {
stock: number;
}
@Injectable({
providedIn: 'root',
})
export class CoffeeService {
private apiUrl = '/api/coffee'; // ASP.NET CoreのAPIエンドポイント
// 現在は非推奨だがバックエンドとの対比のためコンストラクタインジェクションで記載
constructor(private http: HttpClient) { }
getStock(coffeeName: string): Observable<StockResponse> {
return this.http.get<StockResponse>(`${this.apiUrl}/stock?name=${coffeeName}`);
}
}
先輩: Angular の @Injectable() デコレーターは、このクラスが DI の対象となることを示している。providedIn: 'root'とすることで、アプリケーション全体でこのサービスを利用できるようになるんだ。HttpClientも Angular が提供しているサービスで、コンストラクタインジェクションによって利用しているね。
後輩: フロントエンドでも constructor(private http: HttpClient) という形で、必要なサービスを受け取っているんですね!
先輩: その通り。そして、この CoffeeService をコンポーネントで利用する例がこれだ。
import { Component, inject } from '@angular/core'; // inject をインポート
import { CoffeeService } from './coffee.service';
@Component({
selector: 'app-coffee-stock',
templateUrl: './coffee-stock.component.html',
})
export class CoffeeStockComponent {
// inject関数を使ってCoffeeServiceを注入する
private coffeeService = inject(CoffeeService);
// 検索結果を保持するためのプロパティ
searchedCoffeeName: string | null = null;
stock: number | null = null;
// テンプレートから直接コーヒー名を受け取る
checkStock(coffeeName: string): void {
this.coffeeService.getStock(coffeeName).subscribe(response => {
this.stock = response.stock;
this.searchedCoffeeName = coffeeName; // 検索した名前を保持
});
}
}
<div>
<h2>コーヒーの在庫を調べる</h2>
<select #coffeeSelect>
<option value="ブラジル産">ブラジル産</option>
<option value="コロンビア産">コロンビア産</option>
<option value="エチオピア産">エチオピア産</option>
</select>
<button (click)="checkStock(coffeeSelect.value)">在庫を確認</button>
@if (searchedCoffeeName) {
<div>
<h3>「{{ searchedCoffeeName }}」の在庫</h3>
<p>在庫数: {{ stock }}</p>
</div>
}
</div>
後輩: このコンポーネントも、コンストラクタでCoffeeServiceを受け取って、そのメソッドを呼び出しているんですね!バックエンドとフロントエンドで、DI の考え方が本当に共通しているのがよく分かりました!
先輩: そうだね。このように、DI の考え方をフルスタックで適用することで、疎結合でテストしやすく、保守性の高いアプリケーションを開発することができるんだ。ASP.NET Core と Angular は、どちらもDIを強力にサポートしているフレームワークだから、この恩恵を最大限に活かしていこう。
つづく・・・
次回「最終回・依存性の注入(DI) 深掘り編 ✍️」