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

アプリ開発

前回の続きです。

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

前回

TODO画面 を作成

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

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

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

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.

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

ng generate component todo --module app
ng generate component todo --module app

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

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

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

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」を修正します。

<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」

export interface Todo {
  id: number;
  title: string;
}

「WebApplication1\Models\Todo.cs」

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テーブルを作成します。

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

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

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

Todoテーブル

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

AspNetUsers

Todoリスト を取得

TodoesController.cs

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

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

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

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

「WebApplication1\Controllers\TodoesController.cs」

// 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」

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」

<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テーブルの値が表示されるはずです。

動作確認

次回

追加、更新、削除

タイトルとURLをコピーしました