ASP.NET と Angular で TodoWebアプリ を作る2

Uncategorized
1k words

前回の続きです。

今回は、認証必須ページの作成をして行きます。

前回

TODO画面 を作成

ログインしていないと開けない TODO画面 を作成します。

まず、Angular CLI を使って「todo」という名前のコンポーネントを生成します。

ClientApp フォルダ内で下記コマンドを実行すると、必要なファイルが作成されます。

1
ng generate component todo

ですが Visual Studio を使った Angular の場合は、エラーが発生します。

エラー

More than one module matches. Use skip-import option to skip importing the component into the closest module.

More than one module matches. Use skip-import option to skip importing the component into the closest module.

その場合、メインモジュールの名前を指定すると解消されます。

1
ng generate component todo --module app

ng generate component todo --module app

TODO画面にログイン必須の設定を付与

ログイン必須の設定を付与して、ブラウザから開けれるようにします。

「app.module.ts」の forRoot に todo画面 を追加します。

1
2
3
4
5
6
7
8
9
10
11
12
imports: [
BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
HttpClientModule,
FormsModule,
ApiAuthorizationModule,
RouterModule.forRoot([
{ path: '', component: HomeComponent, pathMatch: 'full' },
{ path: 'counter', component: CounterComponent },
{ path: 'fetch-data', component: FetchDataComponent, canActivate: [AuthorizeGuard] },
{ path: 'todo', component: TodoComponent, canActivate: [AuthorizeGuard] }
])
],

その時、canActivate に「AuthorizeGuard」を付与することで ログイン必須のページに設定する事が出来ます。

TODO画面へ遷移するリンクを追加

TODO画面を開けれるように メニューにリンクを追加します。

「WebApplication1\ClientApp\src\app\nav-menu\nav-menu.component.html」を修正します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<ul class="navbar-nav flex-grow">
<li class="nav-item"
[routerLinkActive]="['link-active']"
[routerLinkActiveOptions]="{ exact: true }">
<a class="nav-link text-dark" [routerLink]="['/']">Home</a>
</li>
<li class="nav-item" [routerLinkActive]="['link-active']">
<a class="nav-link text-dark" [routerLink]="['/counter']">Counter</a>
</li>
<li class="nav-item" [routerLinkActive]="['link-active']">
<a class="nav-link text-dark" [routerLink]="['/fetch-data']">Fetch data</a>
</li>
<li class="nav-item" [routerLinkActive]="['link-active']">
<a class="nav-link text-dark" [routerLink]="['/todo']">Todo</a>
</li>
</ul>

試しにデバッグ実行をして、TODO画面を開いてみます。

ログインしていない場合はログイン画面が表示され、ログインしている場合は TODO画面 が表示されます。

TODO画面

サーバからデータを取得

自分が持っている TODOデータ をサーバから取得できるようにします。

Todoモデル の作成

クライアント側とサーバ側にTodoモデルを作成します。

クライアント側はTypeScript、サーバ側はC#で作成します。

「WebApplication1\ClientApp\src\app\Todo.ts」

1
2
3
4
export interface Todo {
id: number;
title: string;
}

「WebApplication1\Models\Todo.cs」

1
2
3
4
5
6
7
8
9
10
11
namespace WebApplication1.Models
{
public class Todo
{
[Key]
public int Id { get; set; }
[Required]
public string UserId { get; set; }
public string Title { get; set; }
}
}

Controller の作成

スキャフォールディングを使って、モデルからコントローラーを作成します。

「Controllers」フォルダを選択し、右クリックから 追加 > 新規スキャフォールディングアイテム を選択します。

新規スキャフォールディング

「Entity Framework を使用したアクションがある API コントローラー」を選択します。

Entity Framework を使用したアクションがある API コントローラー

Todoモデルを使ってコントローラーを作ります。

APIコントローラーの追加

データベースを更新

パッケージマネージャーコンソールを使って Todoテーブルを作成します。

1
2
PM> Add-Migration Todo
PM> Update-Database

Update-Database

Todoモデルと同じ型の Todoテーブルが作成されました。

ついでに軽くデータを入れておきます。

Todoテーブル

UserIdは「AspNetUsers」テーブルの Id を使います。

AspNetUsers

Todoリスト を取得

TodoesController.cs

TodoesController を介して Todoリスト を取得できるようにします。

下記コードで、認証済みのログインユーザーIDが取得出来ます。

1
var userId = User.FindFirst(ClaimTypes.NameIdentifier).Value;

取得したユーザーIDを元に、データベースからその人のTODOデータを取得しクライアントに渡します。

「WebApplication1\Controllers\TodoesController.cs」

1
2
3
4
5
6
7
8
9
// GET: api/Todoes
[HttpGet]
public ActionResult<IEnumerable<Todo>> GetTodo()
{
// 認証済みログインユーザーIDを取得
var userId = User.FindFirst(ClaimTypes.NameIdentifier).Value;
// Todoテーブルから認証済みログインユーザーのデータを取得しクライアントに渡します。
return _context.Todo.Where(x => x.UserId == userId).ToList();
}
todo.component.ts

クライアント側の呼び出し処理を書きます。

「WebApplication1\ClientApp\src\app\todo\todo.component.ts」

1
2
3
4
5
6
7
8
export class TodoComponent implements OnInit {
public todoes: Todo[];
constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
http.get<Todo[]>(baseUrl + 'api/todoes').subscribe(result => {
this.todoes = result;
}, error => console.error(error));
}
}
todo.component.html

受け取ったデータを HTML で表示します。

「WebApplication1\ClientApp\src\app\todo\todo.component.html」

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<p *ngIf="!todoes"><em>Loading...</em></p>
<table class='table table-striped' aria-labelledby="tableLabel" *ngIf="todoes">
<thead>
<tr>
<th>No.</th>
<th>Title</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let forecast of todoes">
<td>{{ forecast.id }}</td>
<td>{{ forecast.title }}</td>
</tr>
</tbody>
</table>

動作確認

このように Todoテーブルの値が表示されるはずです。

動作確認

次回

追加、更新、削除