socialgekon.com
  • メイン
  • 革新
  • 設計プロセス
  • リモートの台頭
  • 財務プロセス
バックエンド

Angular5とASP.NETCore

Angularの最初のバージョンがクライアント側のMicrosoftを事実上殺害して以来、私はブログ投稿を書くことを考えていました。 ASP.Net、Webフォーム、MVC Razorなどのテクノロジーは廃止され、MicrosoftではないJavaScriptフレームワークに置き換えられました。ただし、Angularの2番目のバージョン以降、MicrosoftとGoogleは協力してAngular 2を作成してきました。これが、私の2つのお気に入りのテクノロジーが協力し始めたときです。

このブログでは、人々がこれら2つの世界を組み合わせた最高のアーキテクチャを作成できるように支援したいと思います。準備はできたか?さあ!

アーキテクチャについて

RESTful Web API Core2サービスを使用するAngular5クライアントを構築します。



クライアント側:

  • Angular 5
  • Angular CLI
  • Angularマテリアル

サーバー側:

  • .NET C#WebAPIコア2
  • 注入の依存関係
  • JWT認証
  • 最初にエンティティフレームワークコード
  • SQLサーバー

注意

このブログ投稿では、読者がTypeScript、Angularモジュール、コンポーネント、およびインポート/エクスポートの基本的な知識をすでに持っていることを前提としています。この投稿の目的は、コードが時間の経過とともに成長することを可能にする優れたアーキテクチャを作成することです。

あなたは何が必要ですか?

IDEを選択することから始めましょう。もちろん、これは私の好みであり、より快適に感じるものを使用できます。私の場合は、Visual StudioCodeとVisualStudio2017を使用します。

なぜ2つの異なるIDEなのですか? Microsoftがフロントエンド用のVisualStudio Codeを作成したので、このIDEの使用をやめることはできません。とにかく、ソリューションプロジェクト内にAngular 5を統合する方法も説明します。これは、1つのF5だけでバックエンドとフロントの両方をデバッグすることを好む開発者の場合に役立ちます。

バックエンドについては、開発者向けの無料版がありながら非常に完全な最新のVisual Studio2017バージョンであるコミュニティをインストールできます。

したがって、このチュートリアルでインストールする必要があるもののリストは次のとおりです。

  • VisualStudioコード
  • Visual Studio2017コミュニティ (または任意)
  • Node.js v8.10.0
  • SQL Server 2017

注意

node -vを実行して、少なくともノード6.9.xとnpm3.x.xを実行していることを確認します。およびnpm -vターミナルまたはコンソールウィンドウで。古いバージョンではエラーが発生しますが、新しいバージョンでも問題ありません。

フロントエンド

クイックスタート

楽しく始めましょう!最初に行う必要があるのは、Angular CLIをグローバルにインストールすることです。そのため、node.jsコマンドプロンプトを開いて、次のコマンドを実行します。

npm install -g @angular/cli

これで、モジュールバンドラーができました。これは通常、ユーザーフォルダの下にモジュールをインストールします。デフォルトではエイリアスは必要ありませんが、必要に応じて次の行を実行できます。

alias ng='/.npm/lib/node_modules/angular-cli/bin/ng'

次のステップは、新しいプロジェクトを作成することです。私はそれをangular5-appと呼びます。まず、サイトを作成するフォルダーに移動し、次に次の操作を行います。

ng new angular5-app

最初のビルド

ng serve --openを実行するだけで新しいWebサイトをテストできますが、お気に入りのWebサービスからサイトをテストすることをお勧めします。どうして?さて、いくつかの問題は本番環境でのみ発生する可能性があり、ng buildでサイトを構築しますこの環境にアプローチする最も近い方法です。次に、フォルダを開くことができますangular5-app Visual StudioCodeを使用してng buildを実行しますターミナルbash:

初めてAngularアプリを構築する

distという名前の新しいフォルダが作成され、IISまたは任意のWebサーバーを使用して提供できます。次に、ブラウザにURLを入力して、…完了です。

新しいディレクトリ構造

注意

このチュートリアルの目的はWebサーバーのセットアップ方法を示すことではないので、あなたはすでにその知識を持っていると思います。

Angular5ウェルカム画面

srcフォルダ

srcフォルダー構造

私のsrcフォルダは次のように構成されています。app内私たちが持っているフォルダcomponentsここで、Angularコンポーネントごとにcss、ts、spec、およびhtmlを作成します。ファイル。 configも作成しますサイト構成を保持するフォルダーdirectivesすべてのカスタムディレクティブがありますhelpers認証マネージャーのような一般的なコードを格納しますlayoutボディ、ヘッド、サイドパネルなどの主要コンポーネントが含まれますmodelsバックエンドビューモデルと一致するものを保持し、最後にservicesバックエンドへのすべての呼び出しのコードがあります。

appの外フォルダassetsのようにデフォルトで作成されたフォルダを保持しますおよびenvironments、およびルートファイル。

構成ファイルの作成

config.tsを作成しましょうconfig内のファイルフォルダを作成し、クラスAppConfigを呼び出します。ここで、コードのさまざまな場所で使用するすべての値を設定できます。たとえば、APIのURL。クラスはgetを実装していることに注意してください同じ値にアクセスするためのキー/値構造と簡単なメソッドをパラメーターとして受け取るプロパティ。このようにして、this.config.setting['PathAPI']を呼び出すだけで値を簡単に取得できます。それを継承するクラスから。

import { Injectable } from '@angular/core'; @Injectable() export class AppConfig { private _config: { [key: string]: string }; constructor() { this._config = { PathAPI: 'http://localhost:50498/api/' }; } get setting():{ [key: string]: string } { return this._config; } get(key: any) { return this._config[key]; } };

Angularマテリアル

レイアウトを開始する前に、UIコンポーネントフレームワークを設定しましょう。もちろん、Bootstrapのような他のものを使用することもできますが、Materialのスタイリングが好きな場合は、Googleでもサポートされているのでお勧めします。

これをインストールするには、次の3つのコマンドを実行する必要があります。これらのコマンドは、Visual StudioCodeターミナルで実行できます。

npm install --save @angular/material @angular/cdk npm install --save @angular/animations npm install --save hammerjs

2番目のコマンドは、一部のマテリアルコンポーネントがAngularAnimationsに依存しているためです。私も読むことをお勧めします 公式ページ サポートされているブラウザとポリフィルとは何かを理解するため。

3番目のコマンドは、一部のマテリアルコンポーネントがジェスチャをHammerJSに依存しているためです。

これで、app.module.tsで使用するコンポーネントモジュールのインポートに進むことができます。ファイル:

import {MatButtonModule, MatCheckboxModule} from '@angular/material'; import {MatInputModule} from '@angular/material/input'; import {MatFormFieldModule} from '@angular/material/form-field'; import {MatSidenavModule} from '@angular/material/sidenav'; // ... @NgModule({ imports: [ BrowserModule, BrowserAnimationsModule, MatButtonModule, MatCheckboxModule, MatInputModule, MatFormFieldModule, MatSidenavModule, AppRoutingModule, HttpClientModule ],

次のステップはstyle.cssを変更することですファイル、使用したいテーマの種類を追加します。

@import ' [email protected] /material/prebuilt-themes/deeppurple-amber.css';

main.tsにこの行を追加して、HammerJSをインポートします。ファイル:

import 'hammerjs';

そして最後に、不足しているのは、ヘッドセクション内のindex.htmlにマテリアルアイコンを追加することだけです。

layout

レイアウト

この例では、次のような単純なレイアウトを作成します。

レイアウト例

アイデアは、ヘッダーのボタンをクリックしてメニューを開いたり非表示にしたりすることです。 AngularResponsiveが残りの作業を行います。これを行うには、app.componentを作成しますフォルダとその中に置くapp.componentデフォルトで作成されるファイル。ただし、次の画像に示すように、レイアウトの各セクションに同じファイルを作成します。次に、head.component体になります、left-panel.componentヘッダー、およびapp.component.htmlメニュー。

強調表示された構成フォルダー

では、変更しましょう Menu 次のように:

authentication

基本的にhead.component.htmlがありますコンポーネントのプロパティ。ユーザーがログインしていない場合にヘッダーとメニューを削除し、代わりに簡単なログインページを表示できます。

Logout! このように見えます:

left-panel.component.html

ユーザーをログアウトするためのボタンだけです。後でまたこれに戻ります。 Dashboard Users については、今のところHTMLを次のように変更します。

import { Component } from '@angular/core'; @Component({ selector: 'app-head', templateUrl: './head.component.html', styleUrls: ['./head.component.css'] }) export class HeadComponent { title = 'Angular 5 Seed'; }

シンプルにしています。これまでのところ、2つの異なるページをナビゲートするためのリンクは2つだけです。 (これにも後で戻ります。)

さて、これは頭と左側のコンポーネントTypeScriptファイルがどのように見えるかです:

import { Component } from '@angular/core'; @Component({ selector: 'app-left-panel', templateUrl: './left-panel.component.html', styleUrls: ['./left-panel.component.css'] }) export class LeftPanelComponent { title = 'Angular 5 Seed'; } app.component

しかし、appのTypeScriptコードはどうですか?ここに少し謎を残してしばらく一時停止し、認証を実装した後にこれに戻ります。

ルーティング

これで、ページの作成を開始するためのUIとシンプルなレイアウトを支援するAngularMaterialができました。しかし、どうすればページ間を移動できますか?

簡単な例を作成するために、データベース内の既存のユーザーのリストを取得できる「ユーザー」と、統計を表示できる「ダッシュボード」の2つのページを作成しましょう。

app-routing.modules.tsの内部フォルダimport { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { AuthGuard } from './helpers/canActivateAuthGuard'; import { LoginComponent } from './components/login/login.component'; import { LogoutComponent } from './components/login/logout.component'; import { DashboardComponent } from './components/dashboard/dashboard.component'; import { UsersComponent } from './components/users/users.component'; const routes: Routes = [ { path: '', redirectTo: '/dashboard', pathMatch: 'full', canActivate: [AuthGuard] }, { path: 'login', component: LoginComponent}, { path: 'logout', component: LogoutComponent}, { path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] }, { path: 'users', component: UsersComponent,canActivate: [AuthGuard] } ]; @NgModule({ imports: [ RouterModule.forRoot(routes) ], exports: [ RouterModule ] }) export class AppRoutingModule {} というファイルを作成しますこのように見える:

RouterModule

とても簡単です:Routesをインポートするだけですおよび@angular/router /dashboardから、実装するパスをマップできます。ここでは、4つのパスを作成しています。

  • /login:私たちのホームページ
  • /logout:ユーザーが認証できるページ
  • /users:ユーザーをログアウトするための簡単なパス
  • dashboard:バックエンドからユーザーを一覧表示する最初のページ

/に注意してくださいはデフォルトのページであるため、ユーザーがURL canActivateを入力すると、ページは自動的にこのページにリダイレクトされます。また、AuthGuardもご覧ください。パラメータ:ここでは、クラスleft-panel.component.htmlへの参照を作成しています。これにより、ユーザーがログインしているかどうかを確認できます。ログインしていない場合は、ログインページにリダイレクトされます。次のセクションでは、このクラスを作成する方法を説明します。

これで、メニューを作成するだけです。 Dashboard Users を作成したときのレイアウトセクションを覚えておいてくださいこのように見えるファイル?

our.site.url/users

ここが私たちのコードが現実と出会う場所です。これで、コードを作成してURLでテストできます。ダッシュボードページからユーザーに移動できるはずですが、URLを入力するとどうなりますかhttp://www.mysite.com/users/42ブラウザで直接?

画像の代替テキスト

このエラーは、アプリのサイドパネルからそのURLに正常に移動した後でブラウザを更新した場合にも表示されることに注意してください。このエラーを理解するために、参照させてください 公式ドキュメント それが本当に明確なところ:

ルーティングされたアプリケーションはディープリンクをサポートする必要があります。ディープリンクは、アプリ内のコンポーネントへのパスを指定するURLです。たとえば、http://www.mysite.com/は、IDが42のヒーローを表示するヒーロー詳細ページへのディープリンクです。

ユーザーが実行中のクライアント内からそのURLに移動しても、問題はありません。 AngularルーターはURLを解釈し、そのページとヒーローにルーティングします。

ただし、メール内のリンクをクリックするか、ブラウザのアドレスバーに入力するか、ヒーローの詳細ページでブラウザを更新するだけです。これらのアクションはすべて、実行中のアプリケーションの外部でブラウザ自体によって処理されます。ブラウザは、ルーターをバイパスして、そのURLをサーバーに直接要求します。

静的サーバーは、http://www.mysite.com/users/42の要求を受信すると、定期的にindex.htmlを返します。しかし、それは拒否しますsrc代わりにindex.htmlを返すように構成されていない限り、404-NotFoundエラーを返します。

この問題を修正するのは非常に簡単です。サービスプロバイダーのファイル構成を作成するだけです。ここではIISを使用しているので、この環境でそれを行う方法を説明しますが、概念はApacheやその他のWebサーバーでも同様です。

したがって、web.config内にファイルを作成しますangular-cli.jsonというフォルダこれは次のようになります。

{ '$schema': './node_modules/@angular/cli/lib/config/schema.json', 'project': { 'name': 'angular5-app' }, 'apps': [ { 'root': 'src', 'outDir': 'dist', 'assets': [ 'assets', 'favicon.ico', 'web.config' // or whatever equivalent is required by your web server ], 'index': 'index.html', 'main': 'main.ts', 'polyfills': 'polyfills.ts', 'test': 'test.ts', 'tsconfig': 'tsconfig.app.json', 'testTsconfig': 'tsconfig.spec.json', 'prefix': 'app', 'styles': [ 'styles.css' ], 'scripts': [], 'environmentSource': 'environments/environment.ts', 'environments': { 'dev': 'environments/environment.ts', 'prod': 'environments/environment.prod.ts' } } ], 'e2e': { 'protractor': { 'config': './protractor.conf.js' } }, 'lint': [ { 'project': 'src/tsconfig.app.json', 'exclude': '**/node_modules/**' }, { 'project': 'src/tsconfig.spec.json', 'exclude': '**/node_modules/**' }, { 'project': 'e2e/tsconfig.e2e.json', 'exclude': '**/node_modules/**' } ], 'test': { 'karma': { 'config': './karma.conf.js' } }, 'defaults': { 'styleExt': 'css', 'component': {} } }

次に、このアセットがデプロイされたフォルダーにコピーされることを確認する必要があります。 AngularCLI設定ファイルを変更するだけですAuthGuard:

canActivateAuthGuard.ts

認証

クラスがどのように行われたか覚えていますかhelpersルーティング構成を設定するために実装されていますか?別のページに移動するたびに、このクラスを使用して、ユーザーがトークンで認証されているかどうかを確認します。そうでない場合は、ログインページに自動的にリダイレクトされます。このファイルはimport { CanActivate, Router } from '@angular/router'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs/Observable'; import { Helpers } from './helpers'; import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; @Injectable() export class AuthGuard implements CanActivate { constructor(private router: Router, private helper: Helpers) {} canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable | boolean { if (!this.helper.isAuthenticated()) { this.router.navigate(['/login']); return false; } return true; } } — canActivate内に作成しますフォルダを作成し、次のようにします。

Router

したがって、ページを変更するたびに、メソッドHelperが呼び出され、ユーザーが認証されているかどうかが確認されます。認証されていない場合は、helpersが使用されます。ログインページにリダイレクトするインスタンス。しかし、helpers.tsのこの新しい方法は何ですかクラス? localStorageの下フォルダファイルを作成しましょうlocalStorage。ここでは、バックエンドから取得したトークンを格納するsessionStorageを管理する必要があります。

注意

sessionStorageに関しては、CookieまたはlocalStorageを使用することもできます。決定は、実装する動作によって異なります。名前が示すように、sessionStorageブラウザセッションの間のみ使用可能であり、タブまたはウィンドウが閉じられると削除されます。ただし、ページの再読み込み後は存続します。保存しているデータを継続的に利用できるようにする必要がある場合は、localStorage import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { Subject } from 'rxjs/Subject'; @Injectable() export class Helpers { private authenticationChanged = new Subject(); constructor() { } public isAuthenticated():boolean public isAuthenticationChanged():any { return this.authenticationChanged.asObservable(); } public getToken():any { if( window.localStorage['token'] === undefined || window.localStorage['token'] === null || window.localStorage['token'] === 'null' || window.localStorage['token'] === 'undefined' || window.localStorage['token'] === '') { return ''; } let obj = JSON.parse(window.localStorage['token']); return obj.token; } public setToken(data:any):void { this.setStorageToken(JSON.stringify(data)); } public failToken():void { this.setStorageToken(undefined); } public logout():void { this.setStorageToken(undefined); } private setStorageToken(value: any):void { window.localStorage['token'] = value; this.authenticationChanged.next(this.isAuthenticated()); } } よりも望ましいです。 Cookieは主にサーバー側を読み取るためのものですが、Subjectクライアント側でのみ読み取ることができます。したがって、問題は、アプリ内で、誰がこのデータを必要とするか、つまりクライアントとサーバーのどちらであるかということです。


{ path: 'logout', component: LogoutComponent},

私たちの認証コードは今意味がありますか? localStorageに戻ります後でクラスを受講しますが、今はルーティング構成に少し戻ってみましょう。この行を見てください:

components/login

これはサイトからログアウトするためのコンポーネントであり、logout.component.tsをクリーンアップするための単純なクラスです。 import { Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { Helpers } from '../../helpers/helpers'; @Component({ selector: 'app-logout', template:'' }) export class LogoutComponent implements OnInit { constructor(private router: Router, private helpers: Helpers) { } ngOnInit() { this.helpers.logout(); this.router.navigate(['/login']); } } の下に作成しましょう/logoutという名前のフォルダー:

localStorage

したがって、URL login.component.tsにアクセスするたびに、import { Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { TokenService } from '../../services/token.service'; import { Helpers } from '../../helpers/helpers'; @Component({ selector: 'app-login', templateUrl: './login.component.html', styleUrls: [ './login.component.css' ] }) export class LoginComponent implements OnInit { constructor(private helpers: Helpers, private router: Router, private tokenService: TokenService) { } ngOnInit() { } login(): void { let authValues = {'Username':'pablo', 'Password':'secret'}; this.tokenService.auth(authValues).subscribe(token => { this.helpers.setToken(token); this.router.navigate(['/dashboard']); }); } } が削除され、サイトはログインページにリダイレクトされます。最後に、app.component.tsを作成しましょうこのような:

export class AppComponent implements AfterViewInit { subscription: Subscription; authentication: boolean; constructor(private helpers: Helpers) { } ngAfterViewInit() { this.subscription = this.helpers.isAuthenticationChanged().pipe( startWith(this.helpers.isAuthenticated()), delay(0)).subscribe((value) => this.authentication = value ); } title = 'Angular 5 Seed'; ngOnDestroy() { this.subscription.unsubscribe(); } }

ご覧のとおり、現時点では、ここに認証情報をハードコーディングしています。ここではサービスクラスを呼び出していることに注意してください。これらのサービスクラスを作成して、次のセクションでバックエンドにアクセスできるようにします。

最後に、Subjectに戻る必要があります。ファイル、サイトのレイアウト。ここで、ユーザーが認証されている場合はメニューとヘッダーセクションが表示されますが、認証されていない場合は、ログインページのみが表示されるようにレイアウトが変更されます。

Observable

Observableを覚えておいてください私たちのヘルパークラスのクラス?これはauthenticationです。 app.component.html sは、アプリケーションのパブリッシャーとサブスクライバーの間でメッセージを渡すためのサポートを提供します。認証トークンが変更されるたびに、 Menu プロパティが更新されます。 servicesの確認ファイル、それはおそらく今より理にかなっているでしょう:

token.service.ts

サービス

この時点で、さまざまなページに移動し、クライアント側を認証して、非常に単純なレイアウトをレンダリングしています。しかし、どのようにしてバックエンドからデータを取得できますか?からすべてのバックエンドアクセスを行うことを強くお勧めします サービス 特にクラス。私たちの最初のサービスはimport { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Observable } from 'rxjs/Observable'; import { of } from 'rxjs/observable/of'; import { catchError, map, tap } from 'rxjs/operators'; import { AppConfig } from '../config/config'; import { BaseService } from './base.service'; import { Token } from '../models/token'; import { Helpers } from '../helpers/helpers'; @Injectable() export class TokenService extends BaseService { private pathAPI = this.config.setting['PathAPI']; public errorMessage: string; constructor(private http: HttpClient, private config: AppConfig, helper: Helpers) { super(helper); } auth(data: any): any { let body = JSON.stringify(data); return this.getToken(body); } private getToken (body: any): Observable { return this.http.post(this.pathAPI + 'token', body, super.header()).pipe( catchError(super.handleError) ); } } 内にありますTokenServiceと呼ばれるフォルダ:

BaseService

バックエンドへの最初の呼び出しは、トークンAPIへのPOST呼び出しです。トークンAPIはヘッダーにトークン文字列を必要としませんが、別のエンドポイントを呼び出すとどうなりますか?ここでわかるように、import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Observable } from 'rxjs/Observable'; import { of } from 'rxjs/observable/of'; import { catchError, map, tap } from 'rxjs/operators'; import { Helpers } from '../helpers/helpers'; @Injectable() export class BaseService { constructor(private helper: Helpers) { } public extractData(res: Response) { let body = res.json(); return body || {}; } public handleError(error: Response | any) { // In a real-world app, we might use a remote logging infrastructure let errMsg: string; if (error instanceof Response) { const body = error.json() || ''; const err = body || JSON.stringify(body); errMsg = `${error.status} - $error.statusText ${err}`; } else { errMsg = error.message ? error.message : error.toString(); } console.error(errMsg); return Observable.throw(errMsg); } public header() { let header = new HttpHeaders({ 'Content-Type': 'application/json' }); if(this.helper.isAuthenticated()) { header = header.append('Authorization', 'Bearer ' + this.helper.getToken()); } return { headers: header }; } public setToken(data:any) { this.helper.setToken(data); } public failToken(error: Response | any) { this.helper.failToken(); return this.handleError(Response); } } (および一般的なサービスクラス)はsuper.headerから継承しますクラス。これを見てみましょう:

localStorage

したがって、HTTP呼び出しを行うたびに、user.tsを使用してリクエストのヘッダーを実装します。トークンがexport class User { id: number; name: string; } にある場合次に、ヘッダー内に追加されますが、そうでない場合は、JSON形式を設定するだけです。ここで確認できるもう1つのことは、認証が失敗した場合に何が起こるかです。

ログインコンポーネントはサービスクラスを呼び出し、サービスクラスはバックエンドを呼び出します。トークンを取得すると、ヘルパークラスがトークンを管理し、データベースからユーザーのリストを取得する準備が整います。

データベースからデータを取得するには、まず、応答でモデルクラスをバックエンドビューモデルと一致させます。

user.service.ts:

import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Observable } from 'rxjs/Observable'; import { of } from 'rxjs/observable/of'; import { catchError, map, tap } from 'rxjs/operators'; import { BaseService } from './base.service'; import { User } from '../models/user'; import { AppConfig } from '../config/config'; import { Helpers } from '../helpers/helpers'; @Injectable() export class UserService extends BaseService { private pathAPI = this.config.setting['PathAPI']; constructor(private http: HttpClient, private config: AppConfig, helper: Helpers) { super(helper); } /** GET heroes from the server */ getUsers (): Observable { return this.http.get(this.pathAPI + 'user', super.header()).pipe( catchError(super.handleError)); }

そして今、SeedAPI.Web.APIを作成できますファイル:

Web.API

バックエンド

クイックスタート

Web API Core2アプリケーションの最初のステップへようこそ。最初に必要なのは、ASP.Net CoreWebアプリケーションを作成することです。これをViewModelsと呼びます。

新しいファイルの作成

以下に示すように、クリーンスタートには必ず空のテンプレートを選択してください。

空のテンプレートを選択します

以上で、空のWebアプリケーションからソリューションを作成します。これで、アーキテクチャは以下のリストのようになり、さまざまなプロジェクトを作成する必要があります。

現在のアーキテクチャ

これを行うには、それぞれについてソリューションを右クリックし、「クラスライブラリ(.NETCore)」プロジェクトを追加します。

追加する

建築学、建築物、建築様式

前のセクションで8つのプロジェクトを作成しましたが、それらは何のためにありますか?それぞれの簡単な説明は次のとおりです。

  • Interfaces:これは私たちのスタートアッププロジェクトであり、エンドポイントが作成される場所です。ここでは、JWT、インジェクションの依存関係、およびコントローラーを設定します。
  • Commons:ここでは、コントローラーがフロントエンドへの応答で返すデータのタイプから変換を実行します。これらのクラスをフロントエンドモデルと一致させることをお勧めします。
  • Models:これは注入の依存関係を実装するのに役立ちます。静的に型付けされた言語の魅力的な利点は、コンパイラーが、コードが依存するコントラクトが実際に満たされていることを確認できることです。
  • ViewModels:すべての共有動作とユーティリティコードがここに表示されます。
  • Models:データベースをフロントエンド向けのMapsと直接一致させないことをお勧めします。したがって、ViewModelsの目的はフロントエンドから独立したエンティティデータベースクラスを作成することです。これにより、将来、フロントエンドに必ずしも影響を与えることなくデータベースを変更できるようになります。また、単にリファクタリングを実行したい場合にも役立ちます。
  • Models:ここにマップしますServices 〜Repositoriesおよびその逆。このステップは、コントローラーとサービスの間で呼び出されます。
  • App_Start:すべてのビジネスロジックを格納するためのライブラリ。
  • JwtTokenConfig.cs:これはデータベースを呼び出す唯一の場所です。

参照は次のようになります。

参照の図

JWTベースの認証

このセクションでは、トークン認証の基本的な構成を確認し、セキュリティについてもう少し詳しく説明します。

JSON Webトークン(JWT)の設定を開始するには、namespace SeedAPI.Web.API.App_Start { public class JwtTokenConfig { public static void AddAuthentication(IServiceCollection services, IConfiguration configuration) { services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = configuration['Jwt:Issuer'], ValidAudience = configuration['Jwt:Issuer'], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration['Jwt:Key'])) }; services.AddCors(); }); } } } 内に次のクラスを作成しましょう。 appsettings.jsonというフォルダ。内部のコードは次のようになります。

'Jwt': { 'Key': 'veryVerySecretKey', 'Issuer': 'http://localhost:50498/' }

検証パラメータの値は、各プロジェクトの要件によって異なります。構成ファイルの読み取りを設定できる有効なユーザーとオーディエンスConfigureServices:

startup.cs

次に、 // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { DependencyInjectionConfig.AddScope(services); JwtTokenConfig.AddAuthentication(services, Configuration); DBContextConfig.Initialize(services, Configuration); services.AddMvc(); } から呼び出すだけです。 TokenController.csのメソッド:

appsettings.json

これで、'veryVerySecretKey'という最初のコントローラーを作成する準備が整いました。 LoginViewModelで設定した値〜ViewModelsトークンの作成に使用したものと一致する必要がありますが、最初にnamespace SeedAPI.ViewModels { public class LoginViewModel : IBaseViewModel { public string username { get; set; } public string password { get; set; } } } を作成しましょう私たちの内部namespace SeedAPI.Web.API.Controllers { [Route('api/Token')] public class TokenController : Controller { private IConfiguration _config; public TokenController(IConfiguration config) { _config = config; } [AllowAnonymous] [HttpPost] public dynamic Post([FromBody]LoginViewModel login) { IActionResult response = Unauthorized(); var user = Authenticate(login); if (user != null) { var tokenString = BuildToken(user); response = Ok(new { token = tokenString }); } return response; } private string BuildToken(UserViewModel user) { var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config['Jwt:Key'])); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken(_config['Jwt:Issuer'], _config['Jwt:Issuer'], expires: DateTime.Now.AddMinutes(30), signingCredentials: creds); return new JwtSecurityTokenHandler().WriteToken(token); } private UserViewModel Authenticate(LoginViewModel login) { UserViewModel user = null; if (login.username == 'pablo' && login.password == 'secret') { user = new UserViewModel { name = 'Pablo' }; } return user; } } } 事業:

BuildToken

そして最後にコントローラー:

Authenticate

identityDbContextメソッドは、指定されたセキュリティコードでトークンを作成します。 Modelsメソッドには、現時点ではユーザー検証がハードコーディングされていますが、最終的にはデータベースを呼び出して検証する必要があります。

アプリケーションコンテキスト

MicrosoftがCore2.0バージョンをリリースして以来、EntityFrameworkのセットアップは非常に簡単です。 EFコア2 略して。 Contextを使用したコードファーストモデルについて詳しく説明します。最初に、すべての依存関係がインストールされていることを確認してください。 NuGetを使用して管理できます。

依存関係の取得

ApplicationContext.csを使用するここで作成できるプロジェクトIApplicationContext.csフォルダ2つのファイル、EntityBaseおよびEntityBase。また、User.csが必要になりますクラス。

クラス

IdentityUserファイルは各エンティティモデルに継承されますが、namespace SeedAPI.Models { public class User : IdentityUser { public string Name { get; set; } } } はIDクラスであり、namespace SeedAPI.Models.EntityBase { public class EntityBase { public DateTime? Created { get; set; } public DateTime? Updated { get; set; } public bool Deleted { get; set; } public EntityBase() { Deleted = false; } public virtual int IdentityID() { return 0; } public virtual object[] IdentityID(bool dummy = true) { return new List().ToArray(); } } } から継承する唯一のエンティティです。以下は両方のクラスです。

ApplicationContext.cs namespace SeedAPI.Models.Context { public class ApplicationContext : IdentityDbContext, IApplicationContext { private IDbContextTransaction dbContextTransaction; public ApplicationContext(DbContextOptions options) : base(options) { } public DbSet UsersDB { get; set; } public new void SaveChanges() { base.SaveChanges(); } public new DbSet Set() where T : class { return base.Set(); } public void BeginTransaction() { dbContextTransaction = Database.BeginTransaction(); } public void CommitTransaction() { if (dbContextTransaction != null) { dbContextTransaction.Commit(); } } public void RollbackTransaction() { if (dbContextTransaction != null) { dbContextTransaction.Rollback(); } } public void DisposeTransaction() { if (dbContextTransaction != null) { dbContextTransaction.Dispose(); } } } }

これで、App_Startを作成する準備が整いました。これは次のようになります。

Web.API

私たちは本当に近いですが、最初に、今度はnamespace SeedAPI.Web.API.App_Start { public class DBContextConfig { public static void Initialize(IConfiguration configuration, IHostingEnvironment env, IServiceProvider svp) { var optionsBuilder = new DbContextOptionsBuilder(); if (env.IsDevelopment()) optionsBuilder.UseSqlServer(configuration.GetConnectionString('DefaultConnection')); else if (env.IsStaging()) optionsBuilder.UseSqlServer(configuration.GetConnectionString('DefaultConnection')); else if (env.IsProduction()) optionsBuilder.UseSqlServer(configuration.GetConnectionString('DefaultConnection')); var context = new ApplicationContext(optionsBuilder.Options); if(context.Database.EnsureCreated()) { IUserMap service = svp.GetService(typeof(IUserMap)) as IUserMap; new DBInitializeConfig(service).DataTest(); } } public static void Initialize(IServiceCollection services, IConfiguration configuration) { services.AddDbContext(options => options.UseSqlServer(configuration.GetConnectionString('DefaultConnection'))); } } } でさらにクラスを作成する必要がありますnamespace SeedAPI.Web.API.App_Start { public class DBInitializeConfig { private IUserMap userMap; public DBInitializeConfig (IUserMap _userMap) { userMap = _userMap; } public void DataTest() { Users(); } private void Users() { userMap.Create(new UserViewModel() { id = 1, name = 'Pablo' }); userMap.Create(new UserViewModel() { id = 2, name = 'Diego' }); } } } にあるフォルダ事業。最初のクラスはアプリケーションコンテキストを初期化することであり、2番目のクラスは開発中のテストのみを目的としてサンプルデータを作成することです。

// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { DependencyInjectionConfig.AddScope(services); JwtTokenConfig.AddAuthentication(services, Configuration); DBContextConfig.Initialize(services, Configuration); services.AddMvc(); } // ... // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider svp) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } DBContextConfig.Initialize(Configuration, env, svp); app.UseCors(builder => builder .AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials()); app.UseAuthentication(); app.UseMvc(); } App_Start

そして、スタートアップファイルからそれらを呼び出します。

DependencyInjectionConfig.cs

依存性注入

依存性注入を使用して、異なるプロジェクト間を移動することをお勧めします。これは、コントローラーとマッパー、マッパーとサービス、およびサービスとリポジトリの間の通信に役立ちます。

フォルダ内namespace SeedAPI.Web.API.App_Start { public class DependencyInjectionConfig { public static void AddScope(IServiceCollection services) { services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); } } } ファイルを作成しますMapそしてそれはこのようになります:

Service

画像の代替テキスト

新しいエンティティごとに新しいRepository、startup.cs、および// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { DependencyInjectionConfig.AddScope(services); JwtTokenConfig.AddAuthentication(services, Configuration); DBContextConfig.Initialize(services, Configuration); services.AddMvc(); } を作成し、それらをこのファイルと照合する必要があります。次に、namespace SeedAPI.Web.API.Controllers { [Route('api/[controller]')] [Authorize] public class UserController : Controller { IUserMap userMap; public UserController(IUserMap map) { userMap = map; } // GET api/user [HttpGet] public IEnumerable Get() { return userMap.GetAll(); ; } // GET api/user/5 [HttpGet('{id}')] public string Get(int id) { return 'value'; } // POST api/user [HttpPost] public void Post([FromBody]string user) { } // PUT api/user/5 [HttpPut('{id}')] public void Put(int id, [FromBody]string user) { } // DELETE api/user/5 [HttpDelete('{id}')] public void Delete(int id) { } } } から呼び出す必要がありますファイル:

Authorize

最後に、データベースからユーザーリストを取得する必要がある場合、次の依存性注入を使用してコントローラーを作成できます。

Map

Mapsを見てくださいここには、フロントエンドがログインしていることと、クラスのコンストラクターで依存性注入がどのように機能するかを確認するための属性があります。

最終的にデータベースへの呼び出しがありますが、最初にViewModelsを理解する必要があります事業。

UserMap.cs事業

このステップは、マップするだけですnamespace SeedAPI.Maps { public class UserMap : IUserMap { IUserService userService; public UserMap(IUserService service) { userService = service; } public UserViewModel Create(UserViewModel viewModel) { User user = ViewModelToDomain(viewModel); return DomainToViewModel(userService.Create(user)); } public bool Update(UserViewModel viewModel) { User user = ViewModelToDomain(viewModel); return userService.Update(user); } public bool Delete(int id) { return userService.Delete(id); } public List GetAll() { return DomainToViewModel(userService.GetAll()); } public UserViewModel DomainToViewModel(User domain) { UserViewModel model = new UserViewModel(); model.name = domain.Name; return model; } public List DomainToViewModel(List domain) { List model = new List(); foreach (User of in domain) { model.Add(DomainToViewModel(of)); } return model; } public User ViewModelToDomain(UserViewModel officeViewModel) { User domain = new User(); domain.Name = officeViewModel.name; return domain; } } } データベースモデルとの間。エンティティごとに1つ作成する必要があります。前の例に従って、Servicesを例に示します。ファイルは次のようになります。

namespace SeedAPI.Services { public class UserService : IUserService { private IUserRepository repository; public UserService(IUserRepository userRepository) { repository = userRepository; } public User Create(User domain) { return repository.Save(domain); } public bool Update(User domain) { return repository.Update(domain); } public bool Delete(int id) { return repository.Delete(id); } public List GetAll() { return repository.GetAll(); } } }

もう一度、依存性注入がクラスのコンストラクターで機能し、マップをサービスプロジェクトにリンクしているように見えます。

Repositories事業

ここで言うことはあまりありません。この例は非常に単純であり、ここに記述するビジネスロジックやコードはありません。このプロジェクトは、データベースまたはコントローラーのステップの前後にロジックを計算または実行する必要がある場合に、将来の高度な要件で役立つことがわかります。例に従うと、クラスはかなり裸に見えます。

UserRepository.cs

namespace SeedAPI.Repositories { public class UserRepository : BaseRepository, IUserRepository { public UserRepository(IApplicationContext context) : base(context) { } public User Save(User domain) { try { var us = InsertUser(domain); return us; } catch (Exception ex) { //ErrorManager.ErrorHandler.HandleError(ex); throw ex; } } public bool Update(User domain) { try { //domain.Updated = DateTime.Now; UpdateUser(domain); return true; } catch (Exception ex) { //ErrorManager.ErrorHandler.HandleError(ex); throw ex; } } public bool Delete(int id) { try { User user = Context.UsersDB.Where(x => x.Id.Equals(id)).FirstOrDefault(); if (user != null) { //Delete(user); return true; } else { return false; } } catch (Exception ex) { //ErrorManager.ErrorHandler.HandleError(ex); throw ex; } } public List GetAll() { try { return Context.UsersDB.OrderBy(x => x.Name).ToList(); } catch (Exception ex) { //ErrorManager.ErrorHandler.HandleError(ex); throw ex; } } } } 事業

このチュートリアルの最後のセクションに進みます。データベースを呼び出すだけなので、

|_+_|
を作成します。データベース内のユーザーを読み取り、挿入、または更新できるファイル。

|_+_|

概要

この記事では、Angular5とWebAPI Core 2を使用して優れたアーキテクチャを作成する方法を説明しました。この時点で、要件の大幅な増加をサポートするコードを使用して、大規模なプロジェクトのベースを作成しました。

真実は、フロントエンドでJavaScriptと競合するものはなく、バックエンドでSQLServerとEntityFrameworkのサポートが必要な場合、C#と競合できるものは何でしょうか。したがって、この記事のアイデアは、2つの世界の長所を組み合わせることであり、楽しんでいただけたと思います。

次は何ですか?

あなたがのチームで働いている場合 Angular開発者 おそらくフロントエンドとバックエンドで異なる開発者が働いている可能性があるため、両方のチームの取り組みを同期させることは、SwaggerをWeb API2と統合することです。SwaggerはRESTFulAPIを文書化してテストするための優れたツールです。 Microsoftガイドを読む: SwashbuckleとASP.NETCoreの使用を開始する 。

Angular 5をまだ使用しておらず、フォローに問題がある場合は、以下をお読みください。 Angular 5チュートリアル:最初のAngular5アプリのステップバイステップガイド 仲間のApeeScapeerSergeyMoiseevによる。

基本を理解する

フロントエンドの編集にVisualStudioCodeまたはMicrosoftVisual Studioを使用する必要がありますか?

フロントエンドにはどちらのIDEも使用できます。多くの人は、フロントエンドをWebアプリケーションライブラリに参加させて、デプロイを自動化することを好みます。私はフロントエンドコードをバックエンドから分離しておくことを好み、Visual StudioCodeがTypescriptコードにとって特にインテリセンスを備えた非常に優れたツールであることがわかりました。

Angularマテリアルデザインとは何ですか?それを使用する必要がありますか?

Angular MaterialはUIコンポーネントフレームワークであり、使用する必要はありません。 UIコンポーネントフレームワークは、Webサイトのレイアウトとレスポンシブを整理するのに役立ちますが、ブートストラップなどの市場に多数あり、好みのルックアンドフィールを選択できます。

Angularルーティングとナビゲーションとは何ですか?

Angular Routerを使用すると、ユーザーがアプリケーションタスクを実行するときに、あるビューから次のビューへのナビゲーションが可能になります。ブラウザのURLを、クライアントが生成したビューに移動するための命令として解釈できます。開発者はURL名、パラメーターを設定することが許可されており、CanAuthenticateで汚染されているため、ユーザーの認証を検証できます

C#での依存性注入の使用は何ですか?

多くの場合、クラスは相互にアクセスする必要があり、このデザインパターンは、疎結合クラスを作成する方法を示しています。 2つのクラスが緊密に結合されている場合、それらはバイナリアソシエーションでリンクされます。

JWTベースの認証とは何ですか?

JSON Web Token(JWT)は、当事者間で情報をJSONオブジェクトとして安全に送信するためのコンパクトなライブラリです。 JWTは暗号化して、パーティ間の機密性を提供することもできます。署名されたトークンに焦点を当てます。

ツリーカーネル:ツリー構造化データ間の類似性の定量化

データサイエンスとデータベース

ツリーカーネル:ツリー構造化データ間の類似性の定量化
アジャイルドキュメント:スピードと知識保持のバランス

アジャイルドキュメント:スピードと知識保持のバランス

アジャイル

人気の投稿
PHPおよびMySQLでのUTF-8エンコーディングのガイド
PHPおよびMySQLでのUTF-8エンコーディングのガイド
ApeeScapeのトップ無料プログラミング本のリスト
ApeeScapeのトップ無料プログラミング本のリスト
ボタンレスUIデザインの未来
ボタンレスUIデザインの未来
コウノトリ、パート4:ステートメントの実装とまとめ
コウノトリ、パート4:ステートメントの実装とまとめ
iPhoneで本格的なライフスタイル写真を撮影する方法
iPhoneで本格的なライフスタイル写真を撮影する方法
 
Instagramでより多くのいいねを獲得する10の本物の方法
Instagramでより多くのいいねを獲得する10の本物の方法
ARMサーバー:データセンター向けのモバイルCPUアーキテクチャ?
ARMサーバー:データセンター向けのモバイルCPUアーキテクチャ?
あなたの本当に、フリーランスのデザインアドバイス
あなたの本当に、フリーランスのデザインアドバイス
iPhoneで鮮明な商品写真を撮影する方法
iPhoneで鮮明な商品写真を撮影する方法
UI Trends 2020:何が入っていますか?
UI Trends 2020:何が入っていますか?
カテゴリー
財務プロセスリモートの台頭転記ヒントとツールバックエンド革新プロジェクト管理仕事の未来設計プロセス製品ライフサイクル

© 2023 | 全著作権所有

socialgekon.com