Zoo-Blog Webアプリ
ASP Net.core MVC WebアプリMSSQL EF6 IDとBOOSTRAPを使用
スクロールしてアニメルを選択して探索してコメントできるメインカタログページ

について
このASP.Netcore Webアプリは、1つのレイアウトビューを使用したMVCパターンを実証し、NAV BARとレンダリングボディが拡散ビューとコントローラーをレンダリングします。 AnimelsをPageの間でより一般的に探索し、Boostrap Libaryを使用してスタイルを整えるために、1つのビューコンポーネントを含めました
モデル(エンティティフラムワークコア)
MSSQL図

私のモデルには、カテゴリ、動物、コメントの3つのオブジェクトが含まれています。それらのそれぞれに、regexパターン、データ型カスタムメッセージエラーなどを含むいくつかのプロパティとフィッティング検証属性を与えました。
- 動物を検証するための生年月日は150年未満であり、現在の日以前に生まれました
- ファイルバリデーターファイルのコンテンツタイプに「画像」という単語と10MBに制限されたファイルのサイズが含まれているかどうかを確認する
| Public Class ImageFileValidationAttribute : ValidationAttribute |
| { |
| const int max_file_size = 10 * 1024 * 1024 ; // 10MB |
| 保護されたオーバーライド検証isvalid ( object ? value 、 validationContext validationContext ) |
| { |
| if ( valueはiformfileファイル!=デフォルト) |
| { |
| if ( file。length > max_file_size ) |
| new validationResultを返します( 「このファイルのサイズは10MB制限よりも大きい」 ) ; |
| if ( file。contentType。clontains ( " image " ) ) |
| return validationResult 。成功; |
| new validationResultを返します( 「これは有効なファイルではありません」 ) ; |
| } |
| 新しいvalidationResultを返します( 「有効な画像ファイルを入力してください」 ) ; |
| } |
| } |
カテゴリを生成するために、データベースにマッピングされていないが、アパートリエートの選択タグを生成するために使用するヘルパーモデルを作成しました
モデルプロジェクトには、IDがタイプGUIDであるエンティティごとにデータアクセスレイヤーのジェネリックベースレプソトリトリークラスも含まれています。
| public static byte [ ] formfiletobytearray ( formfile formfile ) |
| { |
| if ( formfile != null ) |
| { |
| MemoryStream MemoryStream = new MemoryStream ( ) ; |
| FormFile 。 OpenReadStream ( ) 。 copyto ( memorystream ) ; |
| byte [ ] rawdata = memorystream 。 toArray ( ) ; |
| rawdataを返します。 |
| } |
| デフォルトを返します。 |
| } |
| public static string formatrawdatatoatoimage ( byte [ ] imagesfiledata ) |
| { |
| if ( imagesfiledata != null ) |
| " data:image; base64、" + convert 。 tobase64String ( ImagesFileData ) ; |
| デフォルトを返します。 |
| } |
| |
| } |
ビュー
コントローラーのいくつかのビュー、1つのビューコンポーネント、レイアウトスタイルとスクリプトの3つの有用な部分ビュー、およびナビゲーションバーは、異なるビューとアクションの間をナビゲートするために使用されます
アプリのNAVバー

Create and Updateのマネージャービューには、ブラウザがエラーをスローするのを防ぐために、ファイルタイプとITサイズのVannila JS検証が含まれています
| fileInput 。 addeventListener ( "change" 、 function ( ) { |
| let filesize = this 。ファイル[ 0 ] 。サイズ; |
| if ( this。files [ 0 ] === undefined || filesize === undefined ) { |
| これ。 setcustomvalidity ( "ファイルを入力してください" ) ; |
| これ。 ReportValidity ( ) ; |
| 戻る; |
| } |
| if ( filesize > maxfilesize ) { |
| これ。 setcustomvalidity ( "このファイルは10MBより大きい" ) ; |
| これ。 value = "" ; |
| これ。 ReportValidity ( ) ; |
| 戻る; |
| } |
| if ( ! validfiletype ( this。files [ 0 ] ) ) { |
| これ。 setcustomvalidity ( "これは画像ファイルではありません" ) ; |
| これ。 value = "" ; |
| これ。 ReportValidity ( ) ; |
| 戻る; |
| } |
| if ( filesize < maxfilesize ) { |
| これ。 setcustomvalidity ( "" ) ; |
| これ。 ReportValidity ( ) ; |
| } |
| } ) ; |
コントローラー
このプロジェクトには4つのコントローラーが含まれています。
- ホーム - コメントされた2つの動物を表示します
- マネージャー - 動物のデータのCRUD操作の処理
- カタログ - ブログで動物を表示し、カテゴリごとに並べ替えることができます
- Animelデータ - 動物の詳細を調べて、ユーザーがコメントを残すことができます。コメントの投稿では、ユーザーがコメントを投稿するたびにページをRelloadに防ぐために、Fetch APIを使用します。
| Async関数AddComment (イベント) { |
| コメント= { |
| コメント:未定義、 |
| コンテンツ: ContentTextarea 。価値、 |
| AnimeLid : id 、 |
| } |
| コメント= json 。 Stringify (コメント) ; |
| 待ってフェッチ( ` $ { baseurl } /index` 、 { |
| 方法: 「投稿」 、 |
| ボディ:コメント、 |
| ヘッダー: { |
| 「コンテンツタイプ」 : 「アプリケーション/JSON」 |
| } |
| } ) 。 then ( ( ) => { getAllComments ( ) ; } ) ; |
| } |
Hello Worldコメント

認証&&承認(ID)
ID NUGETと別々のコンテキストを使用して、Webアプリケーションでユーザーを認証および承認し、アプリにLoginModelという名前のモデルヘルパーとサインアップモデルによるヘルパーでの登録とログを使用して、3種類のユーザー「管理者」、「ユーザー」ADN匿名です。マネージャーの役割は、マネージャーコントローラーを使用して、Anchor Nav-Linkを作成と更新することができます。署名されたすべてのユーザーは、アプリケーション内の動物(マネージャーを含む)にコメントできます。匿名のユーザーは、Animelsカタログページをスクロールするか、登録/ログインできます。
アクションの登録:
| [ httppost ] |
| [ valimateantiforgerytoken ] |
| public async task <iactionResult>レジスタ( SignUpModelユーザー) |
| { |
| if ( modelState。ISVALID ) |
| { |
| IdentityUser iduser = new IdentityUser |
| { |
| username = user 。ユーザー名、 |
| PhoneNumber = user 。計画紙、 |
| email = user 。メール |
| } ; |
| var createresult = await _usermanager 。 createasync ( iduser 、 user。password ) ; |
| var addrole = await _usermanager 。 addtoroleasync ( iduser 、 "user" ) ; |
| if ( createresult 。成功) |
| { |
| var signupresult = await _signinmanager 。 passwordsigninasync ( user。username 、 user。passwor 、 false 、 false ) ; |
| if ( signupresult 。成功) |
| { |
| REDIRECTTOACTION ( "index" 、 " home" ) ; |
| } |
| return login ( ) ; |
| } |
| } |
| return View ( ) ; |
| } |
単体テスト
このWebアプリのソリューションには、リポジトリレイヤーのテストの1つのXunitプロジェクトが含まれており、同期メソッドと非同期メソッドの両方のReposiroeyBaseクラスの検証が含まれています。
テスト例:
| [テスト、 requireSthread ] |
| public void findbyidasync ( ) |
| { |
| _CategoryRepository ? 。 create ( categorytest ! ) ; |
| _animelrepository ? 。 create ( animeltest ! ) ; |
| _commentRepository ? 。 create ( commenttest ! ) ; |
| |
| タスク<動物>アニメルフラウンド= _animelrepository ! 。 findbyidasync ( animeltest ! 。id ) ; |
| アニメファウンド。 contionwith ( _ = > { assert。that ( aNimAlFOWND。LESUST 、 IS。equto ( animelTest ) ) ; } ) ; |
| タスク<動物> animelnotfound = _animelRepository 。 findbyidasync ( do_not_insret_animel ! 。id ) ; |
| AnimelNotFound 。続行( _ = > { assert。that ( aNimILFOUND。LESUST 、 IS。NULL ) ; } ) ; |
| タスク<コメント>コメントFound = _commentRepository ! 。 findbyidasync ( commenttest ! 。commentid ) ; |
| コメントファウンド。 contionwith ( _ = > { assert。that ( commentfound。luster 、 is。equitto ( commenttest ) ) ; } ) ; |
| タスク<Category> CategoryFound = _CategoryRepository ! 。 findbyidasync ( categorytest ! 。categoryid ) ; |
| カテゴリファウンド。 contionwith ( _ = > { assert。that ( categoryFound。luster 、 is。equalto ( categorytest ) ) ; } ) ; |
| } |