ASPNET - core2.MVC - Sqlserver.visualstudio2017 Final - Ver2
ASPNET - core2.MVC - Sqlserver.visualstudio2017 Final - Ver2
net/publication/323990640
Seri Belajar ASP.NET: ASP.NET Core 2 MVC & MS SQL Server dengan Visual
Studio 2017
CITATIONS READS
0 2,811
2 authors:
Some of the authors of this publication are also working on these related projects:
All content following this page was uploaded by M Reza Faisal on 24 March 2018.
I
Daftar Isi
Kata Pengantar ............................................................................................... I
Daftar Isi ........................................................................................................ II
Daftar Gambar ............................................................................................. VI
1 Pendahuluan ...............................................................................................12
. NET Core......................................................................................................... 12
ASP.NET Core .........................................................................................................13
Web Server ...............................................................................................................15
Database ............................................................................................................ 18
MS SQL Server 2017 ................................................................................................18
II
Properties .................................................................................................................34
Output ......................................................................................................................35
Error List ..................................................................................................................35
Catatan............................................................................................................... 67
5 Entity Framework Core & MS SQL Server ............................................69
Pendahuluan .................................................................................................... 69
Aplikasi GuestBook........................................................................................ 70
Database First................................................................................................... 70
Project .......................................................................................................................70
Database ...................................................................................................................72
Model ........................................................................................................................75
Controller .................................................................................................................78
Views ........................................................................................................................82
Kesimpulan ...................................................................................................... 98
III
6 ASP.NET Core Identity ...........................................................................100
Pendahuluan .................................................................................................. 100
Project .............................................................................................................. 100
Membuat Project ...................................................................................................101
Konfigurasi Connection String ............................................................................102
Penjelasan Startup.cs ............................................................................................103
Model............................................................................................................... 106
IdentityUser ...........................................................................................................106
IdentityRole ...........................................................................................................107
7 Model-View-Controller ..........................................................................112
Persiapan ......................................................................................................... 112
Aplikasi Book Store ..............................................................................................112
Template Aplikasi Web ........................................................................................112
Membuat Project ...................................................................................................113
Catatan....................................................................................................................115
Model............................................................................................................... 115
API ..........................................................................................................................116
Tipe Class Model ...................................................................................................117
Display & Format ..................................................................................................125
Relasi .......................................................................................................................128
Validasi ...................................................................................................................131
Book Store: Class Model & Atribut.....................................................................134
Class Migrations & Database ..............................................................................142
IV
Sintaks Dasar Razor ..............................................................................................215
HTML Helper ........................................................................................................224
Tag Helper .............................................................................................................235
Book Store: Komponen View ..............................................................................244
V
Daftar Gambar
Gambar 1. Arsitektur ASP.NET. ........................................................................................................ 12
Gambar 2. Daftar file installer .NET 2............................................................................................... 13
Gambar 3. Model-View-Controller. .................................................................................................. 14
Gambar 4. Web API/HTTP Service. .................................................................................................. 14
Gambar 5. Visual Studio Website. ..................................................................................................... 15
Gambar 6. Perbandingan Fitur Visual Studio 2017. ........................................................................ 16
Gambar 7. Visual Studio 2017 pada platform Windows. ............................................................... 16
Gambar 8. Visual Studio 2017 pada platform MacOS. ................................................................... 17
Gambar 9. Visual Studio Code........................................................................................................... 17
Gambar 10. SQL Server 2017 for Windows. ..................................................................................... 18
Gambar 11. Seri Belajar ASP.NET: ASP.NET Core MVC & MySQL.Error! Bookmark not
defined.
Gambar 12. Seri Belajar ASP.NET: ASP.NET Core MVC & PostgreSQL dengan Visual Studio
Code..............................................................................................Error! Bookmark not defined.
Gambar 13. Seri Belajar ASP.NET: Pengenalan ASP.NET Web API.Error! Bookmark not
defined.
Gambar 14. .NET Core 2 – Versi. ....................................................................................................... 20
Gambar 15. Daftar file dan folder project ASP.NET Core Empty. ................................................ 24
Gambar 16. Daftar file dan folder project ASP.NET Core Web. ................................................... 25
Gambar 17. Daftar file dan folder project ASP.NET Core Web dengan otentikasi. ................... 25
Gambar 18. dotnet restore. ................................................................................................................. 26
Gambar 19. dotnet build. .................................................................................................................... 26
Gambar 20. Tampilan aplikasi web ASP.NET Core Empty. .......................................................... 27
Gambar 21. Aplikasi ASP.NET Core Web. ....................................................................................... 27
Gambar 22. Aplikasi ASP.NET Core Web dengan fitur otentikasi. .............................................. 28
Gambar 23. Visual Studio 2017 – Antarmuka installasi. ................................................................ 29
Gambar 24. Visual Studio 2017 – Start Page. ................................................................................... 30
Gambar 25. Visual Studio 2017 – Membuka Project. ...................................................................... 31
Gambar 26. Visual Studio 2017 – Solution Explorer. ...................................................................... 32
Gambar 27. Visual Studio 2017 – Code Editor................................................................................. 32
Gambar 28. Visual Studio 2017 – Visual Editor. .............................................................................. 33
Gambar 29. Visual Studio 2017 – Toolbox. ....................................................................................... 34
Gambar 30. Visual Studio 2017 – Properties. ................................................................................... 35
VI
Gambar 31. Visual Studio 2017 – Output. ........................................................................................ 35
Gambar 32. Visual Studio 2017 – Error List. .................................................................................... 35
Gambar 33. Visual Studio 2017 – Blank solution............................................................................. 36
Gambar 34. Visual Studio 2017 – Blank Solution. ........................................................................... 37
Gambar 35. Visual Studio 2017 – Project. ......................................................................................... 37
Gambar 36. Visual Studio 2017 – Solution & Project. ..................................................................... 38
Gambar 37. Visual Studio 2017 – Template project. ....................................................................... 38
Gambar 38. Visual Studio 2017 – Tipe aplikasi yang dapat dikembangkan dengan bahasa Visual
C#. .................................................................................................................................................. 39
Gambar 39. Visual Studio 2017 – Daftar template project Web dengan C#. .............................. 40
Gambar 40. Visual Studio 2017 – Membuat Blank Solution. ......................................................... 40
Gambar 41. Visual Studio 2017 – Menambah project ke dalam solution..................................... 41
Gambar 42. Visual Studio 2017 – Menambahkan project Console App. ..................................... 41
Gambar 43. Visual Studio 2017 – ConsoleApp1. ............................................................................. 42
Gambar 44. Visual Studio 2017 – Menambahkan project web. ..................................................... 42
Gambar 45. Visual Studio 2017 – Template project web ASP.NET 4.6.1. .................................... 43
Gambar 46. Visual Studio 2017 – Menambahkan project web application. ................................ 43
Gambar 47. Visual Studio 2017 - Add New Item. ........................................................................... 44
Gambar 48. Visual Studio 2017 – Output proses build. ................................................................. 45
Gambar 49. Visual Studio 2017 – Output proses debug................................................................. 45
Gambar 50. Visual Studio 2017 - References. ................................................................................... 46
Gambar 51. Visual Studio 2017 - Reference Manager - Assemblies. ............................................ 46
Gambar 52. Visual Studio 2017 - Refence - Projects. ....................................................................... 47
Gambar 53. Visual Studio 2017 - ConsoleAppNETCore. ............................................................... 48
Gambar 54. Visual Studio 2017 - NuGet Package Manager - Installed. ....................................... 48
Gambar 55. Visual Studio 2017 - NuGet Package Manager - Browse. ......................................... 48
Gambar 56. Visual Studio 2017 - NuGet Package Manager - Search & Install. ........................... 49
Gambar 57. Visual Studio 2017 - NuGet pada Solution Explorer. ................................................ 49
Gambar 58. Solution - ASPNETCoreSQLServer.............................................................................. 50
Gambar 59. Daftar template project ASP.NET Core. ...................................................................... 51
Gambar 60. Template Project: Empty - Add New Project. ............................................................ 52
Gambar 61. Template Project: Empty - Add New Project. ............................................................ 52
Gambar 62. Template Project: Empty - New ASP.NET Core Web Application. ........................ 53
Gambar 63. Template Project: Empty - WebAppEmpty pada Solution Explorer....................... 53
Gambar 64. Template Project: Empty - Package Manager Console.............................................. 55
VII
Gambar 65. Template Project: Empty - Diagnostic Tools............................................................... 56
Gambar 66. Template Project: Empty - WebAppEmpty pada web browser. ............................. 56
Gambar 67. Template Project: Web Application - Add New Project. .......................................... 57
Gambar 68. Template Project: Web Application - New ASP.NET Core Web Application. ...... 57
Gambar 69. Template Project: Web Application - WebAppEmpty pada Solution Explorer. ... 58
Gambar 70. Template Project: Web Application (MVC) - Add New Project. ............................. 59
Gambar 71. Template Project: Web Application (MVC) - New ASP.NET Core Web Application.
........................................................................................................................................................ 59
Gambar 72. Template Project: Web Application (MVC) - WebAppEmpty pada Solution
Explorer. ........................................................................................................................................ 60
Gambar 73. Cara kerja Pattern MVC................................................................................................. 61
Gambar 74. Controller - Menambah class controller. ..................................................................... 61
Gambar 75. Controller - HelloWorldController. ............................................................................. 61
Gambar 76. View - Add MVC View. ................................................................................................ 62
Gambar 77. WebAppMVC - Home. .................................................................................................. 63
Gambar 78. WebAppMVC - HelloWorld. ........................................................................................ 64
Gambar 79. Antarmuka form pada halaman HelloWorld. ............................................................ 64
Gambar 80. Model - Add New Item. ................................................................................................ 65
Gambar 81. Hasil ketika form diisi dan tombol Send diklik. ........................................................ 67
Gambar 82. Catatan 1 tentang ASP.NET Core MVC. ..................................................................... 67
Gambar 83. Catatan 2 tentang ASP.NET Core MVC. ..................................................................... 68
Gambar 84. SqlServerDbFirst - Add New Project. .......................................................................... 70
Gambar 85. SqlServerDbFirst - New ASP.NET Core Web Application. ...................................... 71
Gambar 86. SqlServerDbFirst - Menambah library. ........................................................................ 71
Gambar 87. SqlServerDbFirst - Daftar library yang telah diinstall. .............................................. 72
Gambar 88. SqlServerDbFirst - Membuat database SqlServerDbFirst. ........................................ 72
Gambar 89. SqlServerDbFirst - Membuat tabel Guestbook ........................................................... 73
Gambar 90. SqlServerDbFirst - Tombol save table. ........................................................................ 74
Gambar 91. SqlServerDbFirst - Memberi nama table. .................................................................... 74
Gambar 92. SqlServerDbFirst – Scaffold-DbContext. .................................................................... 75
Gambar 93. SqlServerDbFirst – Add Scaffold.................................................................................. 79
Gambar 94. SqlServerDbFirst – Add MVC Controller with views, using Entity Framework. . 79
Gambar 95. SqlServerDbFirst – Index.cshtml. ................................................................................. 84
Gambar 96. SqlServerDbFirst – Detail.cshtml. ................................................................................ 85
Gambar 97. SqlServerDbFirst – Create.cshtml................................................................................. 86
Gambar 98. SqlServerDbFirst – Edit.cshtml. .................................................................................... 88
VIII
Gambar 99. SqlServerDbFirst – Delete.cshtml. ................................................................................ 89
Gambar 100. SqlServerCodeFirst – Daftar library Entity Framework.......................................... 90
Gambar 101. SqlServerCodeFirst - Migration class......................................................................... 93
Gambar 102. SqlServerCodeFirst - Migrations. ............................................................................... 94
Gambar 103. SqlServerCodeFirst - Add Connection. ..................................................................... 96
Gambar 104. SqlServerCodeFirst - Server Explorer. ....................................................................... 97
Gambar 105. SqlServerCodeFirst - Add MVC Controller with views, using Entity Framework.
........................................................................................................................................................ 97
Gambar 106. SqlServerCodeFirst - Controller & View. .................................................................. 98
Gambar 107. SqlServerIdentity - Membuat project. ...................................................................... 101
Gambar 108. SqlServerIdentity - New ASP.NET Core Web Application. ................................. 101
Gambar 109. SqlServerIdentity - Change Authentication. ........................................................... 102
Gambar 110. SqlServerIdentity - Folder Migrations. .................................................................... 102
Gambar 111. SqlServerIdentity - Antarmuka aplikasi web. ........................................................ 108
Gambar 112. SqlServerIdentity - Form registrasi. ......................................................................... 109
Gambar 113. SqlServerIdentity - Migrations. ................................................................................ 109
Gambar 114. SqlServerIdentity - Login berhasil. .......................................................................... 110
Gambar 115. SqlServerIdentity - Database & table. ...................................................................... 110
Gambar 116. Template admin Gentellela. ...................................................................................... 113
Gambar 117. Book Store - Daftar buku. .......................................................................................... 123
Gambar 118. Display atribut model sebagai label pada header tabel. ....................................... 127
Gambar 119. Display atribut model sebagai label pada form input. .......................................... 127
Gambar 120. Relasi pada tabel. ........................................................................................................ 128
Gambar 121. SqlServerBookStore - Migrations class. ................................................................... 144
Gambar 122. SqlServerBookStore - Database SqlServerBookStore dan table-table. ................. 145
Gambar 123. CategoriesController - Window Add Scaffold. ...................................................... 151
Gambar 124. CategoriesController - Window Add MVC Controller with views, using Entity
Framework. ................................................................................................................................ 152
Gambar 125. AuthorsController - Window Add Scaffold. .......................................................... 160
Gambar 126. AuthorsController - Window Add MVC Controller with views, using Entity
Framework. ................................................................................................................................ 161
Gambar 127. BooksController - Window Add MVC Controller with views, using Entity
Framework. ................................................................................................................................ 169
Gambar 128. BooksController - Daftar buku. ................................................................................ 178
Gambar 129. BooksController - Detail. ........................................................................................... 180
Gambar 130. BooksController - Form menambah buku. ............................................................. 181
IX
Gambar 131. BooksController - Create. .......................................................................................... 182
Gambar 132. BooksController - Edit. .............................................................................................. 185
Gambar 133. BooksController - Delete. .......................................................................................... 190
Gambar 134. File dan folder template gentelella. .......................................................................... 206
Gambar 135. SqlServerBookStore - View - wwwroot. .................................................................. 207
Gambar 136. Layout aplikasi. .......................................................................................................... 207
Gambar 137. Master layout template gentelella. ........................................................................... 208
Gambar 138. Razor - Pesan kesalahan. ........................................................................................... 216
Gambar 139. Razor - Penggunaan simbol @@. ............................................................................... 217
Gambar 140. Razor - Ekspresi implisit & eksplisit. ....................................................................... 219
Gambar 141. Razor - Blok kode. ...................................................................................................... 219
Gambar 142. Razor - Blok kode. ...................................................................................................... 220
Gambar 143. Razor - Pengulangan. ................................................................................................. 222
Gambar 144. Daftar data tamu......................................................................................................... 223
Gambar 145. Tampilan form sebelum proses validasi. ................................................................ 232
Gambar 146. Tampilan form setelah proses validasi. ................................................................... 232
Gambar 147. Antarmuka design form. ........................................................................................... 233
Gambar 148. Contoh antarmuka implementasi tag helper input. .............................................. 240
Gambar 149. Contoh antarmuka implementasi tag helper select. .............................................. 243
Gambar 150. Contoh antarmuka implementasi tag helper select dengan atribut multiple. ... 243
Gambar 151. View Categories - Index.cshtml. ............................................................................... 246
Gambar 152. View Categories - Details.cshtml. ............................................................................ 248
Gambar 153. View Categories - Create.cshtml .............................................................................. 249
Gambar 154. View Categories - Edit. .............................................................................................. 250
Gambar 155. View Categories - Delete. .......................................................................................... 252
Gambar 156. View Authors - Index.cshtml. ................................................................................... 253
Gambar 157. View Authors - Details.cshtml. ................................................................................. 255
Gambar 158. View Authors - Create.cshtml .................................................................................. 256
Gambar 159. View Authors - Edit. .................................................................................................. 258
Gambar 160. View Authors - Delete. .............................................................................................. 259
Gambar 161. View Books - Index.cshtml. ....................................................................................... 261
Gambar 162. View Books - Details.cshtml. .................................................................................... 263
Gambar 163. View Books - Create.cshtml ...................................................................................... 265
Gambar 164. View Books - Edit. ...................................................................................................... 268
Gambar 165. View Books - Delete. .................................................................................................. 270
X
Gambar 166. View Role - Index.cshtml........................................................................................... 273
Gambar 167. View Role - Detail.cshtml. ......................................................................................... 275
Gambar 168. View Role - Create.cshtml ......................................................................................... 276
Gambar 169. View Role - Edit. ......................................................................................................... 278
Gambar 170. View Role - Delete. ..................................................................................................... 280
Gambar 171. View User - Index.cshtml. ......................................................................................... 282
Gambar 172. View User - Detail.cshtml.......................................................................................... 284
Gambar 173. View User - Create.cshtml ......................................................................................... 286
Gambar 174. View User - Edit.......................................................................................................... 288
Gambar 175. View User - Delete...................................................................................................... 290
Gambar 176. Implementasi Keamanan - Form Login. .................................................................. 296
Gambar 177. Implementasi Keamanan - AccessDenied.cshtml. ................................................. 296
Gambar 178. Implementasi Keamanan - Role. .............................................................................. 299
XI
1
Pendahuluan
. NET Core
.NET Framework adalah software framework yang dikembangkan oleh Microsoft. .NET
Framework terdiri atas banyak class library (Framework Class Library) untuk membangun
bermacam aplikasi, seperti aplikasi desktop, aplikasi mobile, aplikasi web dan cloud. Sampai
saat ini .NET Framework telah mencapai versi 4.7.1. .NET Framework ini hanya dapat
digunakan pada platform atau sistem operasi MS Windows. Aplikasi-aplikasi yang dibangun
di atas .NET Framework hanya dapat dijalankan jika pada komputer telah terinstall .NET
Framework. Artinya aplikasi-aplikasi itu hanya akan jalan pada platform MS Windows.
Saat ini Microsoft telah mengembangkan .NET Core, yaitu “.NET Framework” yang bersifat
open-source dan multiplatform. Artinya .NET Core dapat dijalankan pada platform
Windows, Linux dan Mac OS. Sehingga aplikasi-aplikasi yang dibangun di atas framework
ini juga dapat dijalankan di atas banyak platform. Saat ini .NET Core hanya mendukung
bahasa pemrograman C# dan F#. Saat buku ini ditulis.NET Core telah mencapai versi 2.1.4.
Gambar di bawah ini adalah arsitektur sederhana dari kedua framework, yaitu .NET
Framework dan .NET Core.
12
Gambar 2. Daftar file installer .NET 2.
ASP.NET Core
ASP.NET Core merupakan design ulang dari ASP.NET yang telah ada sejak 15 tahun yang
lalu. ASP.NET Core adalah framework untuk membangun aplikasi web, IoT app dan backend
untuk mobile app. Framework ini bersifat open source dan cross-platform, artinya aplikasi
yang dibangun dengan framework ini dapat dijalankan pada sistem operasi Windows, Linux
dan Mac OSX. Aplikasi ASP.NET Core dapat dijalankan di atas .NET Core atau .NET
framework seperti yang terlihat pada gambar di atas.
Dibandingkan dengan ASP.NET versi sebelumnya, ASP.NET Core mempunyai beberapa
perubahan arsitektur. Perubahan ini membuat ASP.NET Core framework menjadi lebih
ramping dan modular. Perbedaan lain adalah ASP.NET Core tidak lagi berbasis pada
System.Web.dll. ASP.NET Core berbasis kepada package-package di NuGet repository. Hal
ini memungkinkan developer untuk melakukan optimasi aplikasi dengan menggunakan
package-package NuGet yang diperlukan. Keuntungan hal ini adalah:
• Aplikasi lebih kecil.
• Aplikasi menjadi lebih aman.
• Mengurangi service.
• Meningkatkan kinerja atau kecepatan.
Tetapi karena ASP.NET Core merupakan framework yang baru saja ditulis, bukan
melanjutkan kode sumber framework sebelumnya, maka tidak semua fitur yang telah ditemui
pada ASP.NET 4.7 akan ditemui pada framework ini.
Saat ini ASP.NET Core framework dapat digunakan untuk membangun aplikasi web dengan
ASP.NET MVC. Selain itu juga dapat digunakan untuk membangun HTTP service dengan
menggunakan ASP.NET Web API.
13
ASP.NET Core MVC
Model-View-Controller (MVC) adalah architectural pattern yang memisahkan aplikasi
menjadi tiga komponen utama yaitu Model, View, dan Controller. Dengan menggunakan
pattern atau pola ini, request atau permintaan user diarahkan ke komponen Controller,
komponen ini bertanggung jawab untuk berkerja dengan komponen Model untuk melakukan
aksi dari user dan/atau mengambil hasil dari query. Komponen Controller memilih
komponen View untuk ditampilkan kepada user. Komponen View juga menyediakan data
Model yang dibutuhkannya.
Model
View Controller
Gambar 3. Model-View-Controller.
ASP.NET Core MVC adalah framework presentasi yang ringan, bersifat open source yang
sangat mudah diuji yang dioptimalkan untuk digunakan dengan ASP.NET Core. Framework
ini menyediakan cara untuk membangun situs web dinamis yang memungkinkan pemisahan
sesuai dengan pola MVC yang telah diterangkan di atas. Framework ini mendukung
pengembangan Test-Driver Development (TDD) dan standar web terbaru.
Web Browser
Business
Database Logic Mobile Device
Desktop Application
14
Web Server
Seperti aplikasi web pada umumnya, aplikasi yang dibangun dengan menggunakan
framework ASP.NET Core juga memerlukan web server untuk agar bisa diakses dari web
browser sebagai web client.
Pada framework ASP.NET sebelumnya digunakan Internet Information Services (IIS) sebagai
web server. Tetapi karena IIS hanya dapat berjalan pada platform Windos maka selain IIS
juga telah disediakan Kestrel sebagai open-source HTTP server dan cross-platform untuk
ASP.NET Core.
Kestrel
Berbeda dengan Apache dan IIS yang didesain untuk banyak kebutuhan umum web server
dan juga dapat mendukung banyak bahasa pemrograman dan banyak fitur seperti browsing
direktori dan lain-lain. Sedangkan Kestrel didesain hanya untuk hosting ASP.NET Core.
Development Tool
Visual Studio adalah adalah sebuah integrated development environment (IDE) yang
dikembangkan oleh Microsoft, yang dapat digunakan untuk mengembangkan aplikasi
Android, iOS, Windows, web dan cloud. Tool ini tersedia untuk berbagai platform yaitu
Windows, Linux dan MacOS.
Visual Studio dapat diunduh di link berikut ini https://www.visualstudio.com/downloads/.
15
Visual Studio 2017
Visual Studio 2017 tersedia dalam tiga pilihan lisensi yaitu Enterprise dan Professional yang
berbayar. Sedangkan Community bersifat gratis. Berikut adalah perbandingan fitur-fitur
yang dimiliki oleh masing-masing versi. Visual Studio 2017 hanya tersedia untuk platform
Windows dan MacOS.
16
Gambar 8. Visual Studio 2017 pada platform MacOS.
17
Database
Database adalah koleksi data yang terorganisir. Database yang sering digunakan adalah
relational database yang merupakan koleksi dari skema, tabel, query dan view. Software yang
memberikan layanan untuk mengelola database dikenal dengan nama Relational Database
Management System (RDBMS) atau Database Server. Saat ini telah banyak tersedia database
server, beberapa diantaranya adalah MS SQL Server, MySQL, dan PostgreSQL.
18
Bahan Pendukung
Buku
Source Code
Source code contoh-contoh yang dibuat pada buku ini dapat diunduh pada repository pada
link berikut ini:
1. https://github.com/rezafaisal/ASPNETCoreSQLServer.
19
2
.NET Core 2 SDK & Runtime
Pada bab ini akan dijelaskan langkah-langkah untuk melakukan installasi .NET Core 2 dan
ASP.NET Core 2 pada sistem operasi Windows.
Installasi
Saat buku ini ditulis telah tersedia:
- .NET Core SDK v2.1.4.
- .NET Core Runtime v2.0.5.
- ASP.NET Core Runtime v2.0.5
Installer tersebut dapat diunduh pada link berikut
https://www.microsoft.com/net/download/.
Proses installasi pada platform Windows dan MacOS sangat mudah, hanya dengan cara
mengeksekusi file installer kemudian ikuti petunjuk yang diberikan pada window installer.
Uji Coba
Untuk uji coba dapat dilakukan dengan mengetikan perintah berikut ini.
dotnet --version
20
.NET Core Command Line Tool
Pada sub bab sebelumnya telah dapat dilihat penggunaan perintah “dotnet”. Perintah ini
adalah perintah utama yang digunakan untuk melakukan hal-hal penting seperti:
1. Membuat project baru.
2. Melakukan migrasi atau upgrade project ke versi yang lebih baru.
3. Melakukan restore library atau package dan tool yang digunakan project.
4. Melakukan build.
5. Melakukan testing.
6. Menjalankan dan mempublish aplikasi.
7. Dan lain-lain.
Pada sub bab ini akan dijelaskan beberapa fungsi penting perintah “dotnet”.
dotnet --info
Product Information:
Version: 2.1.4
Commit SHA-1 hash: 5e8add2190
Runtime Environment:
OS Name: Windows
OS Version: 10.0.16299
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\2.1.4\
Version : 2.0.5
Build : 17373eb129b3b05aa18ece963f8795d65ef8ea54
Sedangkan untuk mengetahui secara lengkap opsi lengkap yang dapat digunakan pada
perintah “dotnet” dapat digunakan perintah berikut.
dotnet --help
path-to-application:
The path to an application .dll file to execute.
SDK commands:
21
new Initialize .NET projects.
restore Restore dependencies specified in the .NET project.
run Compiles and immediately executes a .NET project.
build Builds a .NET project.
publish Publishes a .NET project for deployment (including the runtime).
test Runs unit tests using the test runner specified in the project.
pack Creates a NuGet package.
migrate Migrates a project.json based project to a msbuild based project.
clean Clean build output(s).
sln Modify solution (SLN) files.
add Add reference to the project.
remove Remove reference from the project.
list List reference in the project.
nuget Provides additional NuGet commands.
msbuild Runs Microsoft Build Engine (MSBuild).
vstest Runs Microsoft Test Execution Command Line Tool.
Common options:
-v|--verbosity Set the verbosity level of the command. Allowed values are
q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic].
-h|--help Show help.
sdk-options:
--version Display .NET Core SDK version.
--info Display .NET Core information.
-d|--diagnostics Enable diagnostic output.
runtime-options:
--additionalprobingpath <path> Path containing probing policy and assemblies to probe
for.
--fx-version <version> Version of the installed Shared Framework to use to
run the application.
--roll-forward-on-no-candidate-fx Roll forward on no candidate shared framework is
enabled.
--additional-deps <path> Path to additonal deps.json file.
Membuat Project
Untuk membuat project dengan perintah “dotnet” digunakan opsi “new”. Untuk mengetahui
informasi bantuan cara pembuatan project dapat digunakan perintah berikut.
Options:
-h, --help Displays help for this command.
-l, --list Lists templates containing the specified name. If no name is
specified, lists all templates.
-n, --name The name for the output being created. If no name is specified, the
name of the current directory is used.
-o, --output Location to place the generated output.
-i, --install Installs a source or a template pack.
-u, --uninstall Uninstalls a source or a template pack.
--type Filters templates based on available types. Predefined values are
"project", "item" or "other".
--force Forces content to be generated even if it would change existing
files.
-lang, --language Specifies the language of the template to create.
Options:
-h, --help Displays help for this command.
22
-l, --list Lists templates containing the specified name. If no name is
specified, lists all templates.
-n, --name The name for the output being created. If no name is specified, the
name of the current directory is used.
-o, --output Location to place the generated output.
-i, --install Installs a source or a template pack.
-u, --uninstall Uninstalls a source or a template pack.
--type Filters templates based on available types. Predefined values are
"project", "item" or "other".
--force Forces content to be generated even if it would change existing
files.
-lang, --language Specifies the language of the template to create.
Examples:
dotnet new mvc --auth Individual
dotnet new console
dotnet new --help
Dari informasi di atas dapat dilihat daftar template project yang dapat dibuat. Dari daftar
tersebut terdapat 7 project dan 1 solution. Ada dua pilihan bahasa pemrograman yang dapat
dipergunakan yaitu C# dan F#. Hal yang paling penting dari daftar template di atas adalah
bagian “Short Name”, karena nilai pada kolom ini yang dipergunakan untuk menentukan
tipe project yang akan dibuat nanti.
Untuk melihat seluruh daftar template dapat dilihat perintah berikut ini.
23
dotnet new [short name] -lang [language] -o [folder name]
Sebagai contoh untuk membuat aplikasi console dengan bahasa pemrograman F# digunakan
perintah berikut ini.
Jika opsi –lang tidak digunakan, maka akan digunakan nilai default dari opsi ini yaitu bahasa
pemrograman C#.
Untuk membuat project aplikasi web tersedia 2 template yang dapat digunakan yaitu:
- ASP.NET Core Empty, template ini digunakan untuk membuat aplikasi web kosong.
- ASP.NET Core Web App, template ini digunakan untuk membuat aplikasi web
lengkap.
Untuk membuat aplikasi web dengan menggunakan template ASP.NET Core Empty
digunakan perintah perintah berikut ini.
Hasilnya dapat dilihat di dalam folder webempty dengan isi sebagai berikut.
Gambar 12. Daftar file dan folder project ASP.NET Core Empty.
Sedangkan untuk membuat project ASP.NET Web App dapat dilakukan dengan dua cara.
Cara pertama dengan perintah berikut ini.
Hasilnya dapat dilihat di dalam folder webmvc dengan isi sebagai berikut.
24
Gambar 13. Daftar file dan folder project ASP.NET Core Web.
Project di atas menghasilkan aplikasi web ASP.NET Core MVC yang memiliki komponen
Controller dan View, tetapi tanpa komponen Model. Aplikasi ini juga belum menggunakan
database untuk mengelola user dan fitur otentikasi.
Untuk membuat aplikasi web dengan fitur otentikasi dapat digunakan perintah berikut ini.
Gambar 14. Daftar file dan folder project ASP.NET Core Web dengan otentikasi.
Dari gambar di atas dapat dilihat aplikasi ini memiliki komponen Model, View dan
Controller. Selain itu juga dapat dilihat file webmvcauth.db yang merupakan file database
SQLite.
Restore
Setelah project dibuat maka langkah selanjutnya adalah melakan proses restore library,
package atau tool yang digunakan project. Caranya terlebih dahulu masuk ke folder project
yang ingin direstore kemudian jalankan perintah berikut ini.
dotnet restore
25
Hasilnya dapat dilihat pada gambar di bawah ini.
Build
Selanjutnya adalah melakukan proses build atau kompilasi source code yang ada di dalam
project. Perintah yang digunakan adalah sebagai berikut.
dotnet build
Run
Untuk menjalankan aplikasi digunakan perintah ini.
dotnet run
26
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
Dari informasi di atas dapat dilihat, untuk mengakses aplikasi pada web browser dapat
dilakukan dengan mengetikkan alamat http://localhost:5000 pada address bar web browser.
Untuk menghentikan aplikasi dapat dilakukan dengan cara menekan tombol Ctrl+C.
27
Gambar 19. Aplikasi ASP.NET Core Web dengan fitur otentikasi.
Pada gambar di atas dapat dilihat tambahan menu Register dan Login pada kanan atas dari
halaman web.
Migrasi Project
Pada era Visual Studio 2015, project ASP.NET dan ASP.NET Core menggunakan file
configurasi yang disimpan dalam file project.json. Tetapi untuk Visual Studio 2017 dan .NET
Core SDK terbaru sudah tidak mengenal file konfigurasi project.json. File konfigurasi
digantikan oleh file *.csproj. Sebagai contoh untuk aplikasi web project webmvcauth
menggunakan file konfigurasi webmvcauth.csproj.
Untuk project yang masih menggunakan file konfigurasi project.json, maka tidak akan bisa
menggunakan “dotnet restore” dari .NET Core SDK terbaru, karena perintah ini tidak
menemukan file *.csproj.
Oleh karena itu perlu ada migrasi project yang dapat dilakukan dengan dua cara. Yang
pertama adalah dengan cara membuat project tersebut dengan Visual Studio 2017 tapi cara in
hanya dapat dilakukan pada platform MS Windows saja. Cara yang kedua yang dapat
dilakukan pada semua platform, yaitu dengan menggunakan perintah berikut.
dotnet migrate
28
3
Visual Studio 2017
Pada bab ini diberikan panduan penggunaan Visual Studio dimulai dengan membuat
solution dan project. Kemudian dilanjutkan proses eksekusi. Panduan dicontohkan dengan
menggunakan Visual Studio 2017.
Installasi
Installer Visual Studio 2017 dapat diunduh di https://www.visualstudio.com/downloads/.
Bagi pembaca yang belum memiliki lisensinya dapat mengunduh Visual Studio Community
2017 yang bersifat gratis.
File installer dengan nama vs_community__647043286.1510626584.exe (nomor di belakang
vs_community__ dapat berbeda-beda tergantung waktu file diunduh) berukuran 1MB
(1.094KB). Installasi Visual Studio bersifat online, sehingga file installernya berukuran kecil.
File-file yang diperlukan akan diunduh secara online saat installasi. Setelah file-file yang
diperlukan selesai diunduh, maka dilanjutkan dengan installasi file-file tersebut.
Berikut adalah antarmuka installer.
29
File yang diunduh saat proses installasi hanya akan disimpan sementara saja, jadi tidak bisa
digunakan ulang untuk installasi di mesin lain. Jika ingin mengunduh seluruh file installasi
maka dapat dilakukan dengan cara mengetikkan perintah berikut ini pada DOS command
prompt.
Jika ingin menyimpan file pada folder D:\VS2017Installer maka dapat diketik seperti kode di
bawah ini.
Proses ini akan mengunduh seluruh file installer. Ukuran total seluruh file installer sekitar
40-50GB.
Catatan
Versi Visual Studio 2017 yang digunakan pada ebook ini adalah versi 15.6.0. Sedangkan
untuk urutan installasi sebaiknya adalah sebagai berikut:
- Visual Studio 2017 ver 15.6.0.
- .NET Core SDK v2.1.4.
- .NET Core Runtime v2.0.5.
- ASP.NET Core Runtime v2.0.5
Antarmuka
Pada sub bab ini memberikan penjelasan tentang antarmuka Visual Studio 2017. Visual
Studio akan menampilkan Start Page ini saat dijalankan.
30
- Open, membuat project dari media penyimpanan lokal atau remote version control
seperti GitHub.
- New Project, membuat project baru.
Seperti aplikasi desktop Windows pada umumnya, terdapat fitur yang umum yang ada yaitu:
- Menu.
- Toolbar.
Setelah salah satu project dibuka maka akan dilihat antarmuka seperti pada gambar di bawah
ini.
Solution Explorer
Solution Explorer dapat dilihat pada bagian kanan atas pada Visual Studio 2017.
31
Gambar 23. Visual Studio 2017 – Solution Explorer.
Solution Explorer menampilkan Solution. Solution dapat berisi satu atau lebih Project. User
dapat melihat daftar file yang dimiliki oleh project. User dapat memilih file yang ingin dilihat.
Editor
Editor berfungsi untuk menambah atau memodifikasi item atau kode baik secara visual
ataupun kode dari file yang dipilih. Pada gambar di bawah ini contoh Code Editor. Code
Editor berfungsi untuk mengedit file text.
32
Gambar 25. Visual Studio 2017 – Visual Editor.
Visual Editor memberikan kemampuan pada user untuk melakukan modifikasi antarmuka
dengan cara drag-n-drop item atau komponen visual.
Toolbox
Tool akan menampilkan item-item yang sesuai dengan file yang sedang aktif.
33
Gambar 26. Visual Studio 2017 – Toolbox.
Sebagai contoh, ketika file HTML dibuka maka akan ditampilkan daftar item-item seperti
yang dilihat pada gambar di sebelah kiri. Sedangkan ketika file Window Form dibuka maka
Toolbox akan menampilkan daftar item seperti pada gambar di sebelah kanan.
Properties
Bagian Properties menampilkan detail informasi dari item yang dipilih pada Editor. Biasanya
informasi yang ditampilkan pada bagian ini berkaitan dengan item yang dipilih saat mode
Visual Editor.
34
Gambar 27. Visual Studio 2017 – Properties.
Gambar di sebelah kanan tidak menampilkan informasi, hal ini terjadi ketika Editor sedang
menampilkan file text. Saat mode Editor Visual, maka dapat dilihat property-property yang
dimiliki oleh file yang sedang dibuka.
Output
Bagian Output menampilkan keluaran dari proses yang dijalankan pada Visual Studio.
Seperti proses build atau kompilasi kode. Selain itu bagian ini juga menampilkan keluaran
dari program yang dijalankan, sebagai contoh keluaran dari program berbasis Command
Line.
Error List
Bagian Error List menampilkan error yang terjadi baik dari kode yang ditulis, atau error yang
terjadi karena program yang dibuat melakukan kesalahan atau mendapatkan pesan error dari
sistem lain. Sebagai ketika program yang dibuat tidak bisa melakukan koneksi ke database.
35
Solution & Project
Solution adalah tempat yang dapat berisi banyak project. Setiap solution akan memiliki
sebuah file *.sln. Setiap solution akan disimpan ke dalam folder dengan nama yang sama
dengan nama solutionnya. Pada Visual Studio, solution dapat dilihat pada bagian Solution
Explorer.
Solution
Pada Visual Studio, solution dapat dibuat dengan dua cara. Yang pertama adalah dengan
membuat solution kosong. Langkah pertama adalah dengan membuat project baru dengan
cara memilih File > New > Project.
36
Gambar 31. Visual Studio 2017 – Blank Solution.
Cara kedua adalah dengan membuat project baru. Untuk mencoba cara ini maka solution di
atas harus ditutup terlebih dahulu. Untuk menutup solution pilih File > Close Solution pada
menu. Hasilnya dapat dilihat pada bagian Solution Explorer yang kembali kosong.
Untuk membuat project dapat dilakukan dengan cara memilih File > New > Project.
37
Gambar 33. Visual Studio 2017 – Solution & Project.
Pada gambar di atas dapat dilihat Solution dengan nama LatihanSolution2 yang didalamnya
terdapat project dengan nama LatihanSolution2.
Penulis menyarankan untuk menggunakan cara pertama, karena sebaiknya nama solution
dibuat berbeda dengan nama project didalamnya.
Project
Pada sub bab sebelumnya telah diperlihatkan cara membuat project dengan Visual Studio.
Visual Studio menyediakan template project yang dikelompokkan berdasarkan bahasa
pemrograman, teknologi atau platform, dan tipe aplikasi.
38
- Visual Basic.
- Visual C++.
- Visual F#.
- R.
- JavaScript.
- Python.
- TypeScript.
Selain itu terdapat pilihan platform yang didukung yaitu:
- SQL Server.
- Azure Data Lake.
- Azure Stream Analytics.
- Game.
Jika sebuah bahasa pemrograman dipilih maka dapat dilihat beberapa kelompok tipe aplikasi
yang dapat dipilih seperti pada gambar di bawah ini.
Gambar 35. Visual Studio 2017 – Tipe aplikasi yang dapat dikembangkan dengan
bahasa Visual C#.
Dengan bahasa pemrograman Visual C# dapat dibangun aplikasi, yaitu:
- Windows Classic Desktop.
- Web.
- Android.
- iOS.
- Dan lain-lain.
Sebagai contoh jika dipilih tipe aplikasi Web maka dapat dilihat daftar template project seperti
pada gambar berikut ini.
39
Gambar 36. Visual Studio 2017 – Daftar template project Web dengan C#.
Selanjutnya akan dijelaskan bagaimana membuat solution kosong kemudian menambahkan
beberapa project didalamnya.
Pertama adalah memastikan tidak ada solution yang sedang dibuka. Kemudian pilih File >
New > Project. Kemudian pada window New Project pilih Installed > Other Project Types >
Visual Studio Solution. Pilih Blank Solution kemudian isi kolom Name dengan nama solution
yang diinginkan. Diakhiri dengan mengklik tombol OK.
40
Gambar 38. Visual Studio 2017 – Menambah project ke dalam solution.
Pilih Add > New Project. Untuk contoh pertama menambahkah project console, dengan cara
memilih Visual C# > Windows Classic Desktop > Console App (.NET Framework).
41
Gambar 40. Visual Studio 2017 – ConsoleApp1.
Project kedua ditambahkan dengan cara yang sama.
42
Gambar 42. Visual Studio 2017 – Template project web ASP.NET 4.6.1.
Sebagai contoh dipilih template Empty kemudian klik tombol OK. Hasilnya dapat dilihat
pada gambar di bawah ini.
43
Item
Item adalah sesuatu yang dapat ditambahkan ke dalam project. Item dapat berupa:
- Class.
- Image.
- File HTML.
- Dan lain-lain.
Untuk menambahkan item pada project dapat dilakukan dengan cara klik kanan pada project
kemudian pilih Add > New Item.
44
Gambar 45. Visual Studio 2017 – Output proses build.
Proses Debug adalah proses untuk menjalankan StartUp project atau project yang diinginkan.
StartUp project biasanya adalah project yang pertama kali dibuat pada solution. Pada
Solution Explorer, StartUp project dapat dibedakan dengan nama project dengan cetak tebal
seperti yang terlihat pada project ConsoleApp1 pada gambar di atas. Jika proses debug
dilakukan dengan cara memilih Debug > Start Debugging maka StartUp project akan
dijalankan oleh Visual Studio.
Sedangkan jika ingin melakukan proses debug pada project yang diinginkan saja maka klik
kanan pada project yang ada di Solution Explorer kemudian pilih Debug > Start new instance.
Status proses debug akan dapat dilihat pada bagian Output. Sebagai contoh dilakukan proses
debug pada project ConsoleApp1.
Reference
Sebuah project memiliki library default. Library default ini akan berbeda-beda antar setiap
tipe project. Sebagai contoh project console akan memiliki library yang berbeda jika
dibandingkan dengan project mobile. Untuk melihat library apa saja yang dimiliki oleh suatu
project, maka dapat dilihat dengan cara membuka References pada project.
45
Gambar 47. Visual Studio 2017 - References.
Pada gambar di atas dapat dilihat bahwa project tipe console memiliki library default dengan
nama namespace berikut ini:
- Microsoft.Csharp.
- System.
- System.Core.
- System.Data.
- System.Data.DataSetExtensions.
- System.Net.Http.
- System.Xml.
- System.Xml.Linq.
Selain library default tersebut, pengguna dapat menambahkan library lain yang tersedia atau
library dari suatu project yang sedang dibangun.
Untuk menambahkan library pada project dapat dilakukan dengan cara klik kanan pada
References di project yang diinginkan. Kemudian pilih Add Reference.
46
Pengguna dapat memilih library dari 3 tipe, yaitu:
- Assembly.
- Project.
- COM.
Pada gambar di atas adalah contoh ketika tab Assemblies aktif. Dapat dilihat daftar assembly
yang tersedia dan juga yang telah digunakan pada project. Assembly yang telah digunakan
pada project memiilki tanda check seperti gambar di atas.
Jika pada solution sedang dikembangkan project tipe class library, maka project tersebut
dapat ditambahkan pada project dengan mengklik tab Projects. Maka dapat dilihat daftar
project yang ada pada solution seperti pada gambar di bawah ini (daftar project akan berbeda
dengan pembaca, dan mungkin kosong jika pada solution hanya ada 1 project utama saja).
Catatan
Tidak semua project memiliki Reference seperti contoh project di atas. Project yang
memiliki Reference adalah project yang dibangun dengan menggunakan .NET Framework.
Sedangkan project yang dibangun dengan menggunakan .NET Core Framework akan
menggunakan cara lain untuk menambahkan library.
NuGet
Untuk project yang dibangun dengan .NET Core Framework maka salah satu cara untuk
menambahkan library dengan menggunakan NuGet. Sebagai contoh, pada gambar di bawah
ini terdapat project dengan nama ConsolAppNETCore yang dibuat dengan menggunakan
template project Console App (.NET Core).
47
Gambar 50. Visual Studio 2017 - ConsoleAppNETCore.
Jika dibandingkan dengan project ConsolApp pada sub bab sebelumnya, terlihat perbedaan
struktur project ini. Pada project ini tidak terdapat References. Sebagai gantinya pada project
ini terdapat Dependencies yang berisi library-library yang digunakan oleh project ini.
Untuk menambahkan library pada project ini dapat menggunakan NuGet. Caranya klik
kanan pada project kemudian pilih Manage NuGet Packages.
48
Jika ingin mencari library yang diinginkan, maka bisa mengetikan kata kunci pada kolom
Search.
Gambar 53. Visual Studio 2017 - NuGet Package Manager - Search & Install.
Misal library yang diinginkan telah ditemukan adalah MySql.Data, klik library tersebut maka
di samping kanan daftar dapat dilihat informasi detail dari library tersebut. Jika ingin
menginstallnya maka klik tombol Install. Kemudian ikutan instruksi selanjutnya.
49
4
ASP.NET Core
Membuat Solution
Seluruh contoh project yang diberikan pada buku ini akan disimpan di dalam sebuah
solution. Cara pembuatan solution telah dicontohkan pada bab sebelumnya. Dengan cara
yang sama buat solution dengan nama ASPNETCoreSQLServer.
50
- React.js and Redux.
51
Gambar 57. Template Project: Empty - Add New Project.
Kemudian akan ditampilkan window Add New Project seperti pada gambar di bawah ini.
52
Gambar 59. Template Project: Empty - New ASP.NET Core Web Application.
Kemudian pilih Empty dan klik tombol OK. Hasilnya dapat dilihat pada Solution Explorer.
53
namespace WebAppEmpty
{
public class Startup
{
// This method gets called by the runtime. Use this method to add
services to the container.
// For more information on how to configure your application, visit
https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
}
namespace WebAppEmpty
{
public class Program
{
public static void Main(string[] args)
54
{
BuildWebHost(args).Run();
}
Pada aplikasi standalone pasti terdapat file Program.cs yang didalamnya terdapat class
Program dengan sebuah method Main. Method Main adalah utama yang akan dipanggil
ketika aplikasi standalone dijalankan. Isi method Main pada file di atas berisi kode untuk
melakukan proses hosting aplikasi menjalankan web server. Web server yang umumnya
digunakan oleh ASP.NET Core adalah Kestrel.
Setelah project dibuat, maka langkah selanjutnya adalah melakukan proses restore yang
bertujuan untuk memuat library-library yang sesuai dengan template project yang
digunakan. Untuk melakukan proses restore dapat dilakukan dengan menuliskan perintah
pada Package Manager Console. Console ini dapat diaktifkan dengan cara memilih Tools >
NuGet Package Manager > Package Manager Console pada menu.
Hasilnya akan dapat dilihat pada bagian bawah antarmuka Visual Studio seperti pada
gambar di bawah ini.
dotnet restore
Jika proses berhasil, maka untuk melakukan proses build dan menjalankan project dapat
dilakukan dengan cara klik kanan pada project yang ada di Solution Explorer. Kemudian
pilih Debug > Start new instance.
Saat proses debug akan terjadi perubahan antarmuka pada Visual Studio 2017 seperti pada
gambar berikut.
55
Gambar 62. Template Project: Empty - Diagnostic Tools.
Dan secara otomatis akan dijalankan web broser yang menampilkan aplikasi web dari project
yang dijalankan.
56
Gambar 64. Template Project: Web Application - Add New Project.
Setelah window New ASP.NET Core Web Application ditampilkan pilih Web Application
kemudian klik tombol OK.
Gambar 65. Template Project: Web Application - New ASP.NET Core Web
Application.
Selanjutnya dapat dilihat project WebAppRazor pada Solution Explorer.
57
Gambar 66. Template Project: Web Application - WebAppEmpty pada Solution
Explorer.
Selanjutnya lakukan kembali proses restore project dengan perintah “dotnet” seperti yang
telah diterangkan pada sub bab sebelumnya.
Dari gambar di atas terdapat tambahan sebuah folder dan dua file, yaitu:
- Folder Pages, folder ini berisi file *.cshtml. File ini adalah file Razor. Pembahasan
tentang Razor akan diberikan pada bab selanjutnya.
- File appsettting.json, file ini berfungsi untuk menyimpan setting aplikasi seperti
konfigurasi untuk koneksi ke database dan lain-lain.
- File bundleconfig.json, file ini berfungsi untuk menentukan cara untuk melakukan
proses bundling dan minification terhadapa project.
58
Gambar 67. Template Project: Web Application (MVC) - Add New Project.
Gambar 68. Template Project: Web Application (MVC) - New ASP.NET Core Web
Application.
Pada window New ASP.NET Web Applicatin pilih template Web Application (Model-View-
Controller.
59
Gambar 69. Template Project: Web Application (MVC) - WebAppEmpty pada
Solution Explorer.
Hasilnya dapat dilihat pada Solution Explorer. Pada gambar di atas dapat dilihat bahwa
project WebAppMVC memiliki folder dan file tambahan jika dibandingkan dengan dengan
dua project sebelumnya. Folder yang ditambahkan adalah:
- Model, folder ini menyimpan komponen Model
- View, folder ini menyimpan komponen View.
- Controller, folder ini menyimpan komponen Controller.
Ketiga folder tersebut adalah folder penting pada framework Model-View-Controller. Detail
tentang framework ini akan dibahas pada bab selanjutnya.
60
Gambar 70. Cara kerja Pattern MVC.
Untuk menjelaskan cara kerja pattern MVC dan fungsi-fungsi folder ASP.NET Core MVC
yang telah disebutkan di atas, maka pada sub bab ini akan diberikan contoh project sederhana.
Project ini melanjutnya project WebAppMVC yang telah dibuat sebelumnya.
Controller
Langkah pertama adalah membuat komponen controller. Komponen controller disimpan
pada folder Controllers. Untuk membuat class controller, klik kanan pada folder Controller
di project WebAppMVC, kemudian Add > Controller. Maka akan ditampilkan window Add
Scaffold seperti pada gambar di bawah ini.
namespace WebAppMVC.Controllers
{
public class HelloWorldController : Controller
{
public IActionResult Index()
{
return View();
}
}
}
Dari kode di atas dapat dilihat bahwa class HelloWorldController merupakan turunan dari
class Controller. Hal ini juga akan berlaku untuk semua class controller yang akan dibuat
nanti. Di dalam class HelloWorldController dapat dilihat sebuah method Index yang
merupakan implementasi dari IActionResult. Di dalam method Index dapat dilihat
pemanggilan method View. Method ini berfungsi untuk menampilkan komponen View.
Nama file komponen View yang dipanggil oleh method Index ini adalah Index.cshtml
View
Langkah selanjutnya adalah membuat komponen View. Komponen View disimpan di dalam
folder Views. Selanjutnya buat folder HelloWorld di dalam folder Views. Nama folder
HelloWorld ini disesuaikan dengan nama class controller yaitu HelloWorldController. Jika
nama class controller adalah StudentController, maka harus dibuat folder Student
Untuk setiap method action pada class controller harus dibuat sebuah file *.cshtml dengan
nama yang sesuai dengan nama method action tersebut. Sebagai contoh jika pada class
HelloWorldController dimiliki satu method action dengan nama Index, maka perlu dibuat
file Index.cshtml di dalam folder Views\HelloWorld.
62
Untuk membuat file Index.cshtml, klik kanan pada folder Views\HelloWorld kemudian pilih
Add > View. Kemudian akan ditampilkan window Add MVC View seperti gambar di atas.
Ketik nama file pada kolom View name. Nama file sesuai dengan nama method action yaitu
Index. Kemudian klik tombol Add.
Berikut adalah isi dari file Index.cshtml.
Index.cshtml
@{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
Hello World!
Pada file tersebut dapat ditambahkan “Hello World!”. Untuk melihat halaman ini dapat
dilakukan dengan menjalankan aplikasi ini, yaitu klik kanan pada project WebAppMVC
kemudian pilih Debug > Start new instance.
Berikut adalah halaman yang ditampilkan.
Karena alamat halaman utama dari WebAppMVC adalah http://localhost:56400 maka alamat
yang ditulis untuk mengakses halaman HelloWorld adalah sebagai berikut.
http://localhost:56400/HelloWorld
63
Gambar 75. WebAppMVC - HelloWorld.
Model
Pada bagian ini akan diperkenalkan tentang komponen model. Penjelasan tentang komponen
ini dalam bentuk contoh kasus yaitu dengan membuat halaman aplikasi web sederhana
dengan tampilan seperti pada gambar di bawah ini. Fungsi halaman web ini hanya untuk
mengirimkan nama, email dan pesan. Kemudian nilai-nilai yang diisi itu akan ditampilkan
kembali pada halaman web.
64
Gambar 77. Model - Add New Item.
Pada window Add New Item, pilih Code > Class. Kemudian berikan nama class pada kolom
Name. Nama class yang dibuat adalah Pesan.cs dengan isi sebagai berikut.
Pesan.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace WebAppMVC.Models
{
public class Pesan
{
public String Name { set; get; }
public String Message { set; get; }
}
}
Selanjutnya akan dimodifikasi kode file Index.cshtml untuk membuat form seperti pada
gambar di atas. Berikut ini adalah kode yang digunakan.
Index.cshtml
@model WebAppMVC.Models.Pesan
@{
ViewData["Title"] = "Index";
}
<h2>Pesan</h2>
<div>
@using (Html.BeginForm())
{
<p>
@Html.LabelFor(m => m.Name)
@Html.TextBoxFor(m => m.Name)
</p>
65
<p>
@Html.LabelFor(m => m.Message)
@Html.TextBoxFor(m => m.Message)
</p>
<p>
@ViewBag.Pesan
</p>
<p>
<input type="submit" value="Send" />
</p>
}
</div>
Pada kode di atas dapat dilihat cara pembutan form dengan menggunakan sintaks Razor.
Pada sub bab selanjutnya akan diberikan penjelasan detail tentang sintaks Razor. Hal penting
pada kode di atas adalah bagaimana cara menentukan komponen model yang digunakan
pada komponen view. Dapat dilihat komponen model ditulis dengan menulis lengkap nama
class berserta namespace.
@model WebAppMVC.Models.Pesan
Setelah langkah di atas perlu dilakuan modifikasi pada class controller untuk menangani aksi
ketika tombol Send ditekan. Berikut ini adalah hasil modifikasi pada class controller
HelloWorldController.cs.
HelloWorldController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using WebAppMVC.Models;
namespace WebAppMVC.Controllers
{
public class HelloWorldController : Controller
{
[HttpGet]
public IActionResult Index()
{
return View();
}
[HttpPost]
public IActionResult Index(Pesan data)
{
ViewBag.Pesan = data.Name + " mengatakan " + data.Message;
return View();
}
}
}
Pada komponen controller ini juga harus dipanggil komponen model dengan cara sebagai
berikut.
using WebAppMVC.Models;
66
Pada file class HelloWorldController.cs dapat dilihat terdapat dua method action Index.
Method action Index yang pertama menggunakan method GET, artinya method akan
memberikan respon saat diakses dengan method GET. Sedangkan ketika diakses dengan
method POST, sebagai contoh saat tombol Send diklik, maka method action Index method
POST yang akan digunakan.
Berikut adalah tampilan halaman setelah tombol Send diklik.
Gambar 78. Hasil ketika form diisi dan tombol Send diklik.
Catatan
Berdasarkan dari gambar cara kerja pattern MVC di awal sub bab ini dan penjelasan
implementasi pada ASP.NET Core maka ada dua hal penting yang mesti dicatat, yaitu:
1. Untuk membuat web dengan halaman statik tanpa ada interaksi seperti form atau
penggunaan data maka cukup digunakan dua komponen saja yaitu Controller dan
View.
67
Gambar 80. Catatan 2 tentang ASP.NET Core MVC.
Untuk kasus ini maka komponen yang sebaiknya disiapkan atau dibuat terlebih
dahulu adalah komponen model, komponen controller kemudian komponen view.
3. Catatan lain adalah hal penting terkait cara proses build dan run aplikasi ASP.NET
Core ini. Pastikan jika melakukan modifikasi file selain komponen View, maka harus
dilakukan proses build agar dihasilkan file *.dll terbaru kemudian dilakukan proses
run kembali, agar aplikasi yang ditampilkan menggunakan hasil file *.dll yang
terbaru. Tetapi jika yang dimodifikasi adalah file pada komponen view, seperti file
*.cshtml maka untuk hasil modifikasi dapat langsung dilihat dengan cara melakukan
proses refresh pada Web Browser saja.
68
5
Entity Framework Core &
MS SQL Server
Pada bab ini akan dijelaskan bagaimana cara melakukan koneksi dan operasi ke database MS
SQL Server dari aplikasi web yang dibangun dengan framework ASP.NET Core dan bahasa
pemrograman C#.
Pendahuluan
Entity Framework adalah framework untuk mempermudah mengakses database.
Framework ini awalnya dibangun sebagai bagian dari .NET framework yang hanya dapat
digunakan pada platform Microsoft. Tetapi dengan dikembangkannya .NET Core yang
bersifat multiplatform, maka Entity Framework Core juga dapat digunakan pada berbagai
platform.
Entity Framework Core atau disingkat EF Core adalah object-relational mapper (OR/M) yang
memungkinkan software developer dapat bekerja dengan database dengan object .NET. Hal
ini mengurangi kode program untuk mengakses database, karena digantikan oleh class dan
method yang telah disediakan oleh framework ini.
EF Core mendukung berbagai macam database, tetapi tergantung ketersediaan provider
database. Saat buku ini ditulis telah tersedia provider database sebagai berikut:
1. MS SQL Server.
2. MS SQL Server Compact Edition.
3. SQLite.
4. MySQL, tersedia tiga provider untuk database MySQL yaitu:
o MySQL Official., provider
o MySQL Pomelo.
o MySQL Sapient Guardian.
5. PostgreSQL.
6. Oracle dan lain-lain.
Tetapi tidak semua provider yang disebutkan diatas adalah gratis, ada beberapa provider
database yang bersifat berbayar. Untuk mendapatkan update informasi terbaru tentang
provider database dapat mengunjungi alamat berikut https://docs.microsoft.com/en-
us/ef/core/providers/.
EF Core mendukung dua pendekatan dalam mengembangkan aplikasi, yaitu:
1. Database First, pendekatan ini umum dilakukan dimana database dan tabel-tabel di
dalamnya telah terlebih dahulu dibuat. Kemudian dibuat class model berdasarkan
tabel-tabel di dalam database tersebut
2. Code First, pada pendekatan ini yang dibuat terlebih dahulu adalah class-class model
kemudian tabel-tabel pada database akan secara otomatis dibuat saat pertama kali
aplikasi web dijalankan.
69
Pada bab ini akan dijelaskan contoh implementasi EF Core dengan kedua pendekatan
tersebut.
Aplikasi GuestBook
Implementasi EF Core dengan kedua pendekatan di atas akan dijelaskan dengan memberikan
contoh pembuatan aplikasi yang sama yaitu GuestBook. Tujuannya adalah agar dapat dilihat
perbedaan antara pendekatan Database First dan Code First.
Aplikasi ini adalah aplikasi sederhana yang hanya mempunyai fitur-fitur sebagai berikut:
1. Menampilkan daftar buku tamu.
2. Mengisi buku tamu.
Database First
Pada sub bab ini akan diberikan langkah-langkah implementasi Entity Framework Code
dengan pendekatan Database First.
Project
Pada sub bab ini akan dilakukan pembuatan project dan setting project.
Membuat Project
Langkah pertama adalah membuat project dengan nama SqlServerDbFirst. Untuk membuat
project SqlServerDbFirst gunakan template ASP.NET Core Web Application. Dan ikuti
langkah-langkah membuat project ini seperti yang dijelaskan di bab sebelumnya.
70
Gambar 82. SqlServerDbFirst - New ASP.NET Core Web Application.
Menyiapkan Library
Pada sub bab ini akan dilakukan persiapan project agar project dapat digunakan untuk
melakukan koneksi ke database MS SQL. Library-library yang akan ditambahkan adalah
sebagai berikut:
- Microsoft.EntityFrameworkCore.SqlServer, adalah library EF Core untuk melakukan
koneksi ke database MS SQL Server.
- Microsoft.EntityFrameworkCore.Tools, adalah tool untuk membuat model dari
database.
- Microsoft.VisualStudio.Web.CodeGeneration.Design, adalah tool scaffolding untuk
membuat komponen controller dan view.
Untuk menginstall ketiga library ini dapat dapat menggunakan NuGet Package Manager,
kemudian cari ketiga library tersebut.
71
Untuk memeriksa library yang sudah diinstall, dapat dilihat pada tab Installed yang ada pada
NuGet Package Manager atau pada Solution Explorer pada bagian Dependencies > NuGet
seperti pada gambar di bawah ini.
Database
Langkah kedua adalah membuat database pada MS SQL Server dan membuat konfigurasi
connecting string.
Untuk membuat database pada MS SQL Server, dapat digunakan Microsoft SQL Server
Management Studio yang dapat diunduh di https://go.microsoft.com/fwlink/?linkid=867670.
72
Membuat Database
Langkah pertama adalah membuat database dengan Microsoft SQL Server Management
Studio. Klik kanan pada Databases kemudian pilih New Database. Kemudian ketikkan nama
database pada window New Database seperti pada gambar di atas. Nama database yang
digunakan adalah SqlServerDbFirst. Kemudian klik OK.
Langkah kedua adalah membuat tabel. Pada database SqlServerDbFirst, klik kanan pada
Tables kemudian piliah Table.
73
Gambar 87. SqlServerDbFirst - Tombol save table.
Kemudian berikan nama GuestBook untuk table tersebut.
Koneksi Database
Connection string adalah string yang berisi nilai-nilai yang digunakan untuk melakukan
koneksi ke database. Pada project ASP.NET Core MVC, connection string disimpan pada file
appsettings.json. Berikut adalah kode connection string.
{
"ConnectionStrings": {
"Default": "Server=.\\SQLEXPRESS; Database=SqlServerDbFirst;User
Id=sa;Password=MRezaFaisal;Trusted_Connection=True"
}
}
Jika pada file appsettings.json telah terdapat konfigurasi lain, maka connection string
ditambahkan pada konfigurasi sebelumnya setelah dipisahkan dengan tanda koma. Berikut
adalah isi file appsettings.json secara lengkap.
appsettings.json
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
},
"ConnectionStrings": {
"Default": "Server=.\\SQLEXPRESS;Database=SqlServerDbFirst;User
Id=sa;Password=MRezaFaisal;Trusted_Connection=True"
}
}
74
Model
Langkah selanjutnya adalah membuat class model dan class data context. Kedua class ini
disimpan pada folder Models. Karena telah dibuat table pada database maka pengguna dapat
menggunakan perintah Scaffold-DbContext untuk membuat class entity model dan class data
context.
Untuk menjalankan perintah Scaffold-DbContext digunakan Package Manager Console.
Untuk mengaktifkan console, pilih Tools > NuGet Package Manager > Package Manager
Console.
Kemudian ketikan perintah dengan pola berikut ini.
Scaffold-DbContext "Connection String"
Microsoft.EntityFrameworkCore.SqlServer -OutputDir OUTPUT_FOLDER
Jika isi connection string adalah seperti yang ditulis pada sub bab di atas. Kemudian file-file
akan disimpan pada folder Models. Maka perintahnya dapat diketik sebagai berikut ini.
Scaffold-DbContext "Server=.\SQLEXPRESS;Database=SqlServerDbFirst;User
Id=sa;Password=MRezaFaisal;Trusted_Connection=True"
Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models
namespace SqlServerDbFirst.Models
{
public partial class GuestBook
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Message { get; set; }
}
75
}
Class ini dibuat oleh perintah Scaffold-DbContext karena pada database hanya terdapat tabel
GuestBook saja. Jika pada database itu terdapat 5 table, maka secara otomatis perintah
tersebut akan membuat 5 class entity model untuk masing-masing table. Penjelasan detail
tentang class entity model akan dibahas pada Bab Model-View-Controller sub bab Model.
namespace SqlServerDbFirst.Models
{
public partial class SqlServerDbFirstContext : DbContext
{
public virtual DbSet<GuestBook> GuestBook { get; set; }
Untuk membuat class ini diperlukan library ini Microsoft.EntityFrameworkCore, library ini
adalah untuk implementasi Entity Framework.
76
Nama class adalah bebas, tetapi class harus merupakan turunan dari class DbContext.
public partial class SqlServerDbFirstContext : DbContext
{
}
Langkah selanjutnya adalah membuat agar class entity GuestBook dapat digunakan untuk
melakukan operasi menambah, membaca, mengedit dan menghapus data. Caranya adalah
dengan membuat property GuestBooks dari class data context yang mana tipe propertnya itu
dibentuk dari class DbSet.
Untuk pemetaan antara class entity model dengan tabel dapat dilihat pada method
OnModelCreating. Pemetaan antara tabel ini biasanya dilakukan jika nama class entity
model berbeda dengan nama table yang ada di database. Jika nama keduanya sama maka
tidak perlu dilakukan pemetaan.
Untuk contoh kasus nama class entity yang berbeda dengan nama table, misal nama class
entity adalah GuestBook dan nama table di database adalah buku_tamu maka perlu
dilakukan pemetaan sebagai berikut ini.
modelBuilder.Entity<GuestBook>().ToTable("buku_tamu");
modelBuilder.Entity<GuestBook>().ToTable("NAMA_TABLE");
Sedangkan untuk memetakan antara property-property yang dimiliki oleh class entity model
dengan atribut-atribut yang dimiliki oleh tabel dengan menggunakan kode berikut ini.
modelBuilder.Entity<GuestBook>(entity =>
{
entity.Property(e => e.Email).HasColumnType("nchar(255)");
entity.Property(e => e.Message).HasColumnType("text");
entity.Property(e => e.Name).HasColumnType("nchar(50)");
});
Kasus di atas juga dilakukan jika nama property pada class entity model sama dengan nama
field pada table.
Jika nama property dan field berbeda maka dapat dilakukan pemetaan dengan sintaks umum
sebagai berikut ini.
Kemudian untuk memetakan property yang akan menangani atribut primary key dari tabel
digunakan kode berikut ini.
77
modelBuilder.Entity<NAMA_CLASS>().HasKey(e => new { e.NAMA_PROPERTY });
Class Startup.cs
Telah dijelaskan di atas bahwa pada class ini akan dilakukan penentuan provider database
yang digunakan, dalam hal ini adalah provider database MS SQL Server. Selain itu juga
proses pengambilan nilai connection string untuk digunakan oleh provider database MS SQL
Server.
Pada sub bab ini akan dilakukan registrasi class data context menggunakan dependency
injection pada class Startup.cs. Untuk itu harus dilakukan modifikasi class
SqlServerDbFirstContext.cs dengan cara menghapus method OnConfiguring dan
menambahkan kode berikut ini.
public SqlServerDbFirstContext(DbContextOptions<SqlServerDbFirstContext>
options) : base(options)
{
}
Selanjutnya adalah modifikasi file Startup.cs. Tambahkan kedua namespace ini ke dalam file
tersebut.
using Microsoft.EntityFrameworkCore;
using SqlServerDbFirst.Models;
Kode di atas adalah cara registrasi class SqlServerDbFirstContext pada class Startup.cs. Kode
di atas juga berfungsi untuk membaca konfigurasi connection string pada file
appsettings.json.
Controller
Pada sub bab ini akan dijelaskan cara membuat komponen controller dan view secara
otomatis dengan menggunakan fasilitas dari Visual Studio 2017. Pertama klik kanan pada
folder Controllers kemudian pilih Add > Controller.
Pada window Add Scaffold pilih MVC Controller with views, using Entity Framework seperti
pada gambar di bawah ini.
78
Gambar 90. SqlServerDbFirst – Add Scaffold.
Klik tombol Add kemudian akan ditampilkan window Add MVC Controller with views,
using Entity Framework seperti pada gambar di bawah ini.
Gambar 91. SqlServerDbFirst – Add MVC Controller with views, using Entity
Framework.
Pada window di atas, pilih nilai pada opsi Model class dan Data context class. Berikut adalah
nilai untuk masing-masing opsi:
- Model class, dipilih nilai GuestBook (SqlServerDbFirst.Models).
- Data context class, dipilih nilai SqlServerDbFirstContext (SqlServerDbFirst.Models).
Class controller yang dibuat ini akan disimpan dengan nama GuestBookController sesuai
dengan nilai pada kolom Controller name.
Kemudian klik tombol Add dan hasilnya dapat dilihat pada folder Controllers, terdapat file
GuestBooksController.cs. Berikut ini adalah isi dari file ini.
GuestBooksController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
79
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using SqlServerDbFirst.Models;
namespace SqlServerDbFirst.Controllers
{
public class GuestBooksController : Controller
{
private readonly SqlServerDbFirstContext _context;
// GET: GuestBooks
public async Task<IActionResult> Index()
{
return View(await _context.GuestBook.ToListAsync());
}
// GET: GuestBooks/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
return View(guestBook);
}
// GET: GuestBooks/Create
public IActionResult Create()
{
return View();
}
// POST: GuestBooks/Create
// To protect from overposting attacks, please enable the specific
properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult>
Create([Bind("Id,Name,Email,Message")] GuestBook guestBook)
{
if (ModelState.IsValid)
{
_context.Add(guestBook);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(guestBook);
80
}
// GET: GuestBooks/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
// POST: GuestBooks/Edit/5
// To protect from overposting attacks, please enable the specific
properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id,
[Bind("Id,Name,Email,Message")] GuestBook guestBook)
{
if (id != guestBook.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(guestBook);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!GuestBookExists(guestBook.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(guestBook);
}
// GET: GuestBooks/Delete/5
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
81
return NotFound();
}
return View(guestBook);
}
// POST: GuestBooks/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
var guestBook = await _context.GuestBook.SingleOrDefaultAsync(m
=> m.Id == id);
_context.GuestBook.Remove(guestBook);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
Kemudian pada folder Views akan didapati tambahan folder GuestBooks yang berisi file-file
berikut:
- Create.cshtml.
- Delete.cshtml.
- Detail.cshtml.
- Edit.cshtml.
- Index.cshtml.
Detail tentang file ini akan diberikan pada sub bab selanjutnya.
Views
Telah disebutkan di sub bab sebelumnya bahwa telah dibuat 5 file kompononen views.
Berikut adalah isi masing-masing file tersebut.
Index.cshtml
File ini berfungsi untuk menampilkan daftar data dari table GuestBook.
Index.cshtml
@model IEnumerable<SqlServerDbFirst.Models.GuestBook>
@{
ViewData["Title"] = "Index";
82
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Email)
</th>
<th>
@Html.DisplayNameFor(model => model.Message)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Email)
</td>
<td>
@Html.DisplayFor(modelItem => item.Message)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Id">Details</a>
|
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
83
Gambar 92. SqlServerDbFirst – Index.cshtml.
Detail.cshtml
File ini berfungsi untuk menampilkan daftar data dari table GuestBook.
Detail.cshtml
@model SqlServerDbFirst.Models.GuestBook
@{
ViewData["Title"] = "Details";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Details</h2>
<div>
<h4>GuestBook</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.Name)
</dt>
<dd>
@Html.DisplayFor(model => model.Name)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Email)
</dt>
<dd>
@Html.DisplayFor(model => model.Email)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Message)
</dt>
<dd>
@Html.DisplayFor(model => model.Message)
</dd>
84
</dl>
</div>
<div>
<a asp-action="Edit" asp-route-id="@Model.Id">Edit</a> |
<a asp-action="Index">Back to List</a>
</div>
Create.cshtml
File ini berfungsi untuk menampilkan daftar data dari table GuestBook.
Create.cshtml
@model SqlServerDbFirst.Models.GuestBook
@{
ViewData["Title"] = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Create</h2>
<h4>GuestBook</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-
danger"></div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Email" class="control-label"></label>
85
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Message" class="control-label"></label>
<input asp-for="Message" class="form-control" />
<span asp-validation-for="Message" class="text-
danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default"
/>
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Edit.cshtml
File ini berfungsi untuk menampilkan daftar data dari table GuestBook.
Edit.cshtml
@model SqlServerDbFirst.Models.GuestBook
@{
86
ViewData["Title"] = "Edit";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Edit</h2>
<h4>GuestBook</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-
danger"></div>
<input type="hidden" asp-for="Id" />
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Email" class="control-label"></label>
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Message" class="control-label"></label>
<input asp-for="Message" class="form-control" />
<span asp-validation-for="Message" class="text-
danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
87
Gambar 95. SqlServerDbFirst – Edit.cshtml.
Delete.cshtml
File ini berfungsi untuk menampilkan daftar data dari table GuestBook.
Delete.cshtml
@model SqlServerDbFirst.Models.GuestBook
@{
ViewData["Title"] = "Delete";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Delete</h2>
88
</dd>
</dl>
<form asp-action="Delete">
<input type="hidden" asp-for="Id" />
<input type="submit" value="Delete" class="btn btn-default" /> |
<a asp-action="Index">Back to List</a>
</form>
</div>
Code First
Pada sub bab ini akan diberikan langkah-langkah implementasi Entity Framework Code
dengan pendekatan Code First.
Project
Langkah pertama adalah membuat project dengan nama SqlServerCodeFirst.
Membuat Project
Langkah-langkah pembuatan project SqlServerCodeFirst adalah sama seperti langkah-
langkah membuat project SqlServerDbFirst yang telah dibahas pada sub bab Databaset First.
Setelah project dibuat, ubah status project ini menjadi Startup Project. Caranya adalah dengan
klik kanan pada project SqlServerCodeFirst, kemudian pilih Set as Startup Project.
89
Menyiapkan Library
Library-library yang mesti diinstall pada project ini sama seperti library-library yang
digunakan pada project SqlServerDbFirst. Berikut ini adalah daftar library-library
pendukung Entity Framework yang telah diinstall pada project SqlServerCodeFirst.
Model
Langkah selanjutnya adalah membuat model yaitu class entity model dan class data context.
namespace SqlServerCodeFirst.Models
{
public class GuestBook
{
public int Id { set; get; }
public String Name { set; get; }
public String Email { set; get; }
public String Message { set; get; }
}
}
Kode ini sama dengan kode yang sebelumnya juga dibuat pada sub bab Database First
perbedaannya hanya pada nama namespace yang digunakan yaitu SqlServerDbFirst.Models.
90
Berikut ini adalah kode class data context dengan nama SqlServerCodeFirstContext.cs untuk
implementasi pendekatan Code First.
SqlServerCodeFirstContext.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
namespace SqlServerCodeFirst.Models
{
public class SqlServerCodeFirstContext : DbContext
{
public virtual DbSet<GuestBook> GuestBooks { get; set; }
public
SqlServerCodeFirstContext(DbContextOptions<SqlServerCodeFirstContext>
options) : base(options)
{
}
}
}
Pemetaan yang perlu dilakukan pada method OnModelCreating adalah penentuan property
mana yang akan dijadikan sebagai primary key dengan kode berikut ini.
Langkah selanjutnya adalah membuat agar class entity GuestBook dapat digunakan untuk
melakukan operasi menambah, membaca, mengedit dan menghapus data. Caranya adalah
dengan membuat property GuestBooks dari class data context yang mana tipe property itu
dibentuk dari class DbSet.
Berikut ini adalah kode yang digunakan untuk membuat property GuestBooks.
Class Startup.cs
Isi class ini sama dengan class Startup.cs yang telah dibuat pada pendekatan Database First,
perbedaannya hanya pada namespace SqlServerCodeFirst.
Startup.cs
using System;
91
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.EntityFrameworkCore;
using SqlServerCodeFirst.Models;
namespace SqlServerCodeFirst
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
// This method gets called by the runtime. Use this method to add
services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddDbContext<SqlServerCodeFirstContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("Default")));
}
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
92
Tujuan penambahan namespace di atas adalah agar class-class yang ada di dalam namespace
tersebut dapat diakses pada class Startup.cs ini.
Database
Langkah selanjutnya adalah membuat database dan tabel, tetapi pembuatannya akan
dilakukan secara otomatis.
Connection String
Langkah pertama pada proses ini adalah menambahkan connection string pada file
appsettings.json sebagai berikut.
appsettings.json
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
},
"ConnectionStrings": {
"Default": "Server=.\\SQLEXPRESS; Database=SqlServerCodeFirst;User
Id=sa;Password=MRezaFaisal;Trusted_Connection=True"
}
}
Migration Class
Migration class adalah class yang berisi kode untuk membuat database dan tabel sesuai
dengan appsettings.json dan class entity model. Class ini dibuat secara otomatis dengan
mengunakan perintah dengan sintaks berikut ini.
Add-Migration NAMA_CLASS
Jika nama class adalah InitialCreate maka sintaks di atas menjadi sebagai berikut.
Add-Migration InitialCreate
Perintah ini dapat diketikkan pada Package Manager Console di Visual Studio. Pastikan pilih
SqlServerCodeFirst pada opsi Default project.
93
Hasilnya dapat dilihat akan dibuat folder Migrations seperti pada gambar di bawah ini.
namespace SqlServerCodeFirst.Migrations
{
public partial class InitialCreate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "GuestBooks",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy",
SqlServerValueGenerationStrategy.IdentityColumn),
Email = table.Column<string>(nullable: true),
Message = table.Column<string>(nullable: true),
94
Name = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_GuestBooks", x => x.Id);
});
}
namespace SqlServerCodeFirst.Migrations
{
[DbContext(typeof(SqlServerCodeFirstContext))]
partial class SqlServerCodeFirstContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.0.1-rtm-125")
.HasAnnotation("SqlServer:ValueGenerationStrategy",
SqlServerValueGenerationStrategy.IdentityColumn);
modelBuilder.Entity("SqlServerCodeFirst.Models.GuestBook", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("Email");
b.Property<string>("Message");
b.Property<string>("Name");
b.HasKey("Id");
b.ToTable("GuestBooks");
});
95
#pragma warning restore 612, 618
}
}
}
Karena skema database terbaru direpresentasikan oleh kode pada komponen model, maka EF
Core tidak harus berinteraksi dengan database pada saat proses migrasi dilakukan. Ketika
perintah Add-Migrations dijalankan maka EF Core akan menentukan apa yang diubah
dengan membandingkan model dengan file snapshot ini.
Database
Setelah migration class dibuat, selanjutnya adalah membuat database dan tabel sesuai dengan
migration class tersebut. Pembuatannya dilakukan secara otomatis dengan cara mengetik
perintah ini pada Package Manager Console.
Update-Database
Hasilnya dapat dilihat database SqlServerCodeFirst dan tabel GuestBooks dibuat secara
otomatis. Untuk melihat database dan table ini pada MS SQL server dapat dilakukan melalui
Visual Studio. Caranya adalah dengan klik Tools > Connect to Database. Kemudian isikan
nilai-nilai pada “Server name” dan “Select or enter database name” pada window Add
Connection seperti pada gambar di bawah ini seperti pada gambar di bawah ini.
96
Gambar 101. SqlServerCodeFirst - Server Explorer.
Gambar 102. SqlServerCodeFirst - Add MVC Controller with views, using Entity
Framework.
Hasilnya dapat dilihat seperti pada gambar di bawah ini.
97
Gambar 103. SqlServerCodeFirst - Controller & View.
Dapat dilihat pada folder Controllers telah dibuat class GuestBooksController.cs. Kemudian
pada folder Views dibuat folder GuestBooks yang berisi file view berikut ini:
- Create.cshtml.
- Delete.cshtml.
- Details.cshtml.
- Edit.cshtml.
- Index.cshtml.
Isi dan antarmuka dari file-file tersebut sama seperti pada project SqlServerDbFirst.
Kesimpulan
Pada bab ini dijelaskan cara kerja ASP.NET Core MVC dan cara-cara untuk melakukan
koneksi dan operasi ke database MS SQL Server dari aplikasi web ASP.NET Core MVC
dengan menggunakan Entity Framework Core.
Tujuan pembahasan pada bab ini adalah untuk memberikan pengetahuan perbedaan antara
pendekatan Database First dan Model First yang secara singkat dapat dirangkum sebagai
berikut ini:
1. Pendekatan Database First mempunyai urutan pengerjaan sebagai berikut:
o Membuat database dan table.
o Membuat connection string untuk koneksi ke database dengan menuliskan
nama database yang TELAH dibuat.
o Generate komponen model yang terdiri atas class entity model dan data
context.
o Modifikasi Startup.cs untuk menangani model yang telah dibuat.
o Generate komponen controller dan view berdasarkan komponen model yang
telah dibuat.
98
2. Pendekatan Code First mempunyai urutan pengerjaan sebagai berikut:
o Membuat komponen model. Karena komponen model adalah class yang
terdiri atas kode, maka pendekatan ini disebut sebagai Code First.
o Modifikasi Startup.cs untuk menangani model yang telah dibuat.
o Membuat connection string untuk koneksi ke database dengan menuliskan
nama databae yang AKAN dibuat. Agar pembuatan database bisa dilakukan
konfigurasi connection string harus menggunakan user yang mempunyai
hak akses untuk membuat database. Tapi tentu saja harus hati-hati
menggunakan cara ini untuk alasan keamanan.
o Membuat class Migration.
o Membuat database.
o Membuat komponen controller dan view.
Pada sub bab ini belum dijelaskan secara detail tentang tentang kode-kode pada komponen
model, view dan controller. Penjelasan detail semua kode yang telah dibuat akan dibahas
pada bab selanjutnya.
99
6
ASP.NET Core Identity
Salah satu cara pengamanan yang umum digunakan adalah dengan melindungi halaman
dengan pemeriksaan otentikasi dengan terlebih dahulu melewati halaman login. Sedangkan
otorisasi berfungsi untuk membatasi akses suatu halaman agar hanya dapat diakses oleh user
tertentu saja atau user-user dari role tertentu saja.
Pada bab ini akan dijelaskan dan dipraktekan cara melakukan implementasi otentikasi dan
otorisasi dengan ASP.NET Core dan database MS SQL Server.
Pendahuluan
Pada tahun 2005 telah dikenal ASP.NET Membership yang berfungsi untuk mengelola proses
otentikasi dan otorisasi pada aplikasi web. Tetapi secara default, database yang harus
digunakan adalah SQL Server. Kemudian dikenal pula ASP.NET Universal Provider yang
telah didukung oleh Entity Framework sebagai akses datanya. Tetapi masih memiliki
keterbatasan dalam penggunaan database yaitu hanya dapat menggunakan SQL Server saja.
Penjelasan lebih lanjut dan contoh implementasi ASP.NET Membership dapat dibaca pada
buku berjudul Seri Belajar ASP.NET : Membangun Aplikasi Web Mudah & Cepat dan Seri
Belajar ASP.NET : Membangun Sistem Pengelolaan User.
Sekarang ini telah dikenal ASP.NET Identity, yang memungkinkan pengelolaan proses
otentikasi yang lebih bebas. Termasuk kemampuan untuk melakukan otentikasi atau login
dengan memanfaatkan aku pengguna pada social media seperti facebook, twitter atau yang
lainnya. ASP.NET Identity dapat digunakan pada semua keluarga ASP.NET Framework
seperti ASP.NET MVC, Web Forms, Web Pages, Web API dan SignalR selain itu juga dapat
digunakan untuk berbagai platoform aplikasi seperti web, phone, store atau aplikasi hybrid.
Kedua library di atas menggunakan skema penyimpanan user dan role berdasarkan aturan
yang telah ditentukan oleh library tersebut. Umumnya penyimpanan dilakukan pada
database maka penamaan tabel dan field untuk menyimpan user dan role harus mengikuti
aturan library tersebut. Umumnya pembuatan tabel-tabel tersebut dilakukan secara otomatis
oleh library ini sehingga software developer tidak bisa menambah tabel atau field lain sesuai
kebutuhan.
Kelebihan kedua library tersebut adalah kelengkapan fungsi untuk proses otentikasi dan
otorisasi yang dapat langsung digunakan oleh software developer. Sebagai contoh, telah ada
method untuk proses SignIn dan SignOut yang langsung dapat digunakan.
Project
Pada bab ini akan dilakukan pembuatan dan setting project yang mendukung implementasi
ASP.NET Core Identity.
100
Membuat Project
Berikut adalah langkah-langkah untuk membuat project tersebut.
Klik kanan pada solution ASPNETCoreSqlServer pada solution explorer, kemudian pilih Add
> New Project.
101
Gambar 106. SqlServerIdentity - Change Authentication.
Pada opsi radiobutton pilih Individual User Accounts. Dan pada opsi dropdownlist pilih
Store user accounts in-app. Kemudian klik tombol OK. Dan klik tombol OK lagi pada
window New ASP.NET Core Web Application. Kemudian klik kanan pada project
SqlServerIdentity kemudian pilih Set as Startup Project.
Sebagai informasi, arti dari “Store user account in-app” adalah database akan dibuat dalam
bentuk file yang akan disimpan pada folder di dalam project (umumnya disimpan dalam
folder Data).
Sebagai informasi, project ini menggunakan pendekatan Code First. Hal ini dapat dilihat
pada folder Migrations pada folder Data di project ini.
102
appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-
SqlServerIdentity-D1748F17-8B1A-468A-8054-
A43FC9402DC3;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
}
}
Pada file appsettings.json di atas dapat dilihat bagaimana cara koneksi database yang akan
disimpan dalam bentuk file di dalam project ini. Tetapi karena pembahasan pada buku ini
hanya fokus pada penggunaan database MS SQL Server, maka perlu dilakukan penyesuaian
konfigurasi connection string. Berikut adalah contoh koneksi ke database MS SQL Server.
appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Server=.\\SQLEXPRESS;
Database=SqlServerIdentity;User
Id=sa;Password=MRezaFaisal;Trusted_Connection=True"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
}
}
Penjelasan Startup.cs
Jika file Startup.cs pada project sebelumnya (SqlServerDbFirst dan SqlServerCodeFirst)
dibandingkan dengan file Startup.cs pada project ini (SqlServerIdentity) maka akan dapat
dilihat beberapa perbedaan.
Berikut ini adalah isi file Startup.cs pada project ini.
Startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using SqlServerIdentity.Data;
using SqlServerIdentity.Models;
using SqlServerIdentity.Services;
namespace SqlServerIdentity
{
public class Startup
103
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
// This method gets called by the runtime. Use this method to add
services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))
);
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddMvc();
}
app.UseStaticFiles();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
Perbedaan file ini dengan project sebelumnya adalah terletak method ConfigureServices yaitu
baris yang dicetak tebal.
public void ConfigureServices(IServiceCollection services)
{
104
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))
);
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddMvc();
}
Pada method ini dapat dilihat class data context yang digunakan adalah
ApplicationDbContext. File ini disimpan pada folder Data, berikut adalah isi class
ApplicationDbContext.
ApplicationDbContext.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using SqlServerIdentity.Models;
namespace SqlServerIdentity.Data
{
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext>
options)
: base(options)
{
}
Class data context ini juga berbeda dengan class data context sebelumnya. Pada class data
context sebelumnya adalah turunan dari class DbContext. Sedangkan pada class
ApplicationDbContext di atas adalah turunan IdentityDbContext.
Perbedaan file Startup.cs lainnya ada pada baris berikut ini.
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
Kedua perbedaan yang telah disebutkan di atas merupakan cara untuk implementasi
ASP.NET Core Identity.
105
Model
Implementasi ASP.NET Core Identity membutuhkan database dan tabel-tabel untuk
menyimpan data user dan role. Pendekatan yang dapat digunakan untuk implementasi
adalah Code First, yang artinya diperlukan model untuk mengelola user dan role.
Secara default ASP.NET Core Identity telah memiliki class model tersebut, yaitu:
- IdentityUser, class untuk mengelola user.
- IdentityRole, class untuk mengelola role.
IdentityUser
Class IdentityUser digunakan untuk mengelola user. Class ini memiliki property-property
untuk menyimpan nilai yang dimiliki oleh user. Berikut adalah property-property yang
dimiliki oleh class ini:
- Id.
- UserName.
- NormalizedUserName.
- Email.
- NormalizedEmail.
- EmailConfirmed.
- PasswordHash.
- SecurityStamp.
- ConcurrencyStamp.
- PhoneNumber.
- PhoneNumberConfirmed.
- TwoFactorEnabled.
- LockoutEnd.
- LockoutEnabled.
- AccessFailedCount.
Selain itu class ini juga memiliki property-property yang berfungsi sebagai relasi dengan
model lain, yaitu:
- Roles.
- Claims.
- Logins.
Selain property class ini juga memiliki method-method sebagai berikut:
- ToString().
- ToString().
- Equals(Object).
- Equals(Object, Object).
- ReferenceEquals(Object, Object).
- GetHashCode().
- GetType().
- MemberwiseClone().
Property-property di atas selain property-property yang berfungsi sebagai relasi akan
menjadi atribut-atribut pada tabel AspNetUsers. Jika ingin menambahkan atribut pada tabel
maka cukup menambahkan property. Cara menambahkan property tidak bisa langsung
dilakukan pada class ini, tetap dapat dilakukan dengan cara membuat class baru yang
mewarisi class IdentityUser. Sebagai contoh dibuat class ApplicationUser sebagai berikut.
106
ApplicationUser.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
namespace SqlServerIdentity.Models
{
// Add profile data for application users by adding properties to the
ApplicationUser class
public class ApplicationUser : IdentityUser
{
public string FullName { get; set; }
public string Address { get; set; }
}
}
Untuk membuat class ApplicationUser mewarisi sifat-sifat class IdentityUser dapat dilihat
pada baris yang dicetak tebal. Kemudian dapat dilihat dua property tambahan berikut ini:
- FullName.
- Address.
Agar class ini digunakan oleh ASP.NET Core Identity untuk melakukan migrasi kode dan
database maka class ini harus didaftarkan pada method ConfigureServices di class Startup.cs
seperti yang telah dibahas pada sub bab sebelumnya.
IdentityRole
Class IdentityRole berfungsi untuk mengelola role. Class ini memiliki property-property
untuk menyimpan nilai yang dimiliki oleh role. Berikut adalah property-property yang
dimiliki oleh class ini:
- Users.
- Id.
- Name.
- NormalizedName.
- ConcurrencyStamp.
Selain itu class ini juga memiliki property-property yang berfungsi sebagai relasi dengan
model lain, yaitu:
- Claims.
Selain property class ini juga memiliki method-method sebagai berikut:
- ToString().
- Equals(Object).
- Equals(Object, Object).
- ReferenceEquals(Object, Object).
- GetHashCode().
- GetType().
- MemberwiseClone().
Property-property pada kelompok pertama akan menjadi atribut-atribut pada tabel
AspNetRoles. Seperti halnya penjelasan class IdentityUser, class IdentityRole juga dapat
107
dimodifikasi untuk menambahkan atribut-atribut pada tabel AspNetRoles. Cara
modifikasinya adalah dengan membuat class turunan dari class IdentityRoles.
Database
Karena class Migrations telah dibuat secara otomatis saat membuat project, maka selanjutnya
adalah update database untuk membuat database beserta table-tablenya. Pada bab
sebelumnya telah diperkenalkan cara update database dengan perintah Update-Database.
Tetapi pada sub bab ini akan dicontohkan cara update database tanpa cara tersebut.
Migrasi
Caranya adalah dengan langsung menjalankan project SqlServerIdentity dengan cara klik
kanan pada project kemudian piliah Debug > Start new instance. Berikut adalah antarmuka
aplikasi web ini.
108
Gambar 109. SqlServerIdentity - Form registrasi.
109
Gambar 111. SqlServerIdentity - Login berhasil.
Jika ingin melihat database dan table yang telah dibuat, dapat dilakukan dengan melakukan
koneksi ke database dengan memanfaatkan fitur Connect to Database dari Visual Studio 2017.
Table
Berikut ini adalah table-table yang dibuat pada database SqlServerIdentity.
110
- AspNetUserRoles berfungsi untuk menyimpan relasi antara user dengan role. Pada
ASP.NET Identity, seorang user dapat memiliki 1 atau lebih role. Sebagai contoh,
seorang user dapat memiliki role sebagai Admin saja. Atau memiliki role sebagai
Admin dan User sekaligus.
111
7
Model-View-Controller
Pada bab ini akan diterangkan detail tentang komponen-komponen pada MVC pada
ASP.NET Core MVC dengan cara membuat aplikasi web book store. Aplikasi ini merupakan
aplikasi web sederhana tetapi dengan antarmuka seperti aplikasi web yang umum dibangun
saat ini. Aplikasi book store ini akan menggunakan pembangunan aplikasi dengan
pendekatan Code First dan implementasi ASP.NET Identity.
Persiapan
Aplikasi Book Store
Aplikasi ini akan memiliki fitur-fitur sebagai berikut:
1. Mengelola role.
Fitur ini dapat digunakan untuk menampilkan, menambah, mengedit dan
menghapus role.
2. Mengelola user.
Fitur ini digunakan untuk menampilkan, menambah, mengedit dan menghapus user.
3. Mengelola pengarang buku.
Fitur ini dapat digunakan untuk menampilkan, menambah, mengedit dan
menghapus data pengarang buku.
4. Mengelola kategori buku.
Fitur ini dapat digunakan untuk menampilkan, menambah, mengedit dan
menghapus data kategori buku.
5. Mengelola buku.
Fitur ini dapat digunakan untuk menampilkan, menambah, mengedit dan
menghapus data buku.
112
Gambar 113. Template admin Gentellela.
Tujuan dari penggunaan template ini agar pembaca nantinya memiliki pengetahuan
bagaimana memodifikasi template tersebut agar bisa digunakan dalam membangun aplikasi
web dengan ASP.NET Core.
Template admin yang digunakan pada buku ini adalah Gentellela yang menggunakan
framework Bootstrap 3. Template ini dapat diunduh dari link berikut
https://github.com/puikinsh/gentelella. Cara untuk mengubah template ini agar bisa
digunakan pada aplikasi web ASP.NET Core akan dijelaskan pada sub bab View.
Membuat Project
Nama project yang akan dibuat adalah SqlServerBookStore. Pembuatan project sama seperti
langkah-langkah pembuatan project pada bab ASP.NET Core Identity. Setelah project dibuat
klik kanan pada project kemudian Set as Startup Project.
Modifikasi appsettings.json
Modifikasi appsettings.json dilakukan untuk mengubah koneksi ke database MS SQL Server.
appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Server=.\\SQLEXPRESS;
Database=SqlServerBookStore;User
Id=sa;Password=MRezaFaisal;Trusted_Connection=True"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
}
}
113
Modifikasi Startup.cs
Modifikasi file Startup.cs dilakukan untuk menunjukkan cara melakukan konfigurasi
ASP.NET Core Identity. Berikut ini adalah kode file Startup.cs sebelum dimodifikasi.
Startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using SqlServerBookStore.Data;
using SqlServerBookStore.Models;
using SqlServerBookStore.Services;
namespace SqlServerBookStore
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
// This method gets called by the runtime. Use this method to add
services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))
);
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddMvc();
}
114
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
Perbedaan kode di atas adalah perubahan penggunaan class model IdentityRole menjadi class
model ApplicationRole. Class model ApplicationRole adalah modifikasi class IdentityRole
yang bertujuan untuk menambahkan property. Pembuatan class model ApplicationRole akan
dilakukan pada sub bab Model.
Perbedaan lainnya adalah konfigurasi format password. Pada konfigurasi itu format
password dengan panjang minimal 6 karakter, ijin untuk tidak menggunakan angka dan
karakter spesial dan ijin untuk tidak menggunakan kombinasi huruf besar dan kecil.
Catatan
Untuk proses modifikasi file class data context dan pembuatan class entity model
(ApplicationUser dan ApplicationRole) akan dilakukan di akhir pembahasan Model.
Kemudian dilanjutkan proses pembuatan kode migrasi. Kemudian dilanjutkan dengan
proses pembuatan database dan tabel secara otomatis.
Model
Pada bab Pengenalan ASP.NET Core MVC sub bab Cara Kerja ASP.NET Core MVC, telah
dibuat sebuah class model yaitu class GuestBook. Pada contoh pertama, class model
GuestBook hanya digunakan untuk melakukan pertukaran data antar komponen MVC tanpa
ada pengambilan dan penyimpanan data dari dan ke database. Kemudian pada bab Entity
115
Framework Core & MS SQL Server, diberikan contoh dimana class model GuestBook
dimodifikasi agar memiliki property-property yang sesuai dengan atribut-atribut pada tabel.
Kemudian class model tersebut dapat digunakan untuk membuat tabel dengan bantuan tool
pada Entity Framework Core. Selainnya class model digunakan untuk menampung data dari
database untuk ditampilkan pada komponen view. Class ini juga digunakan untuk
menampung data dari komponen view untuk akhirnya disimpan ke dalam database.
Dari contoh-contoh tersebut, dalam bahasa sederhana maka dapat disimpulkan class model
berfungsi sebagai class yang digunakan untuk membuat tabel dan penampung data dalam
proses operasi data.
Pada bab ini akan dijelaskan bagaimana membuat model yang mendukung pendekatan Code
First dimana class model digunakan untuk melakukan migrasi database dan membuat tabel.
Karena pada umumnya tabel yang digunakan pada suatu aplikasi memiliki relasi, maka pada
sub bab ini akan diberikan membuat class model yang memiliki relasi sehingga saat proses
migrasi database akan dibuat tabel yang juga memiliki relasi.
Kemudian juga akan diberikan fungsi dan manfaat lain yang dimiliki oleh class model yaitu:
- Nilai label yang ditampilkan pada form atau header tabel pada komponen view.
- Validasi nilai yang dimasukkan pada form sebelum diproses dan disimpan ke dalam
database.
Sebagaimana pada bab sebelumnya, class-class model yang dibuat pada sub bab ini akan
disimpan di dalam folder Models pada project.
API
Pada bab sebelumnya telah diperlihatkan cara membuat komponen model dalam bentuk class
model yaitu class GuestBook. Class model GuestBook adalah class model yang sederhana.
Pada bab ini akan dijelaskan cara untuk membuat class model dengan menggunakan
konfigurasi yang lebih lengkap untuk membangun komponen model yang mendukung
relational database, validasi dan label pada antarmuka komponen view.
Untuk melakukan konfigurasi tersebut dapat digunakan dua library atau API, yaitu:
1. Data annotations.
2. Fluent API.
Data Annotations
Cara konfigurasi dengan menggunakan data annotations dilakukan dengan menambahkan
atribut pada class model. Untuk menambahkan atribut pada class model, maka di class
tersebut harus menggunakan namespace berikut ini.
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
116
Fluent API
Konfigurasi class model dengan Fluent API dilakukan pada file class terpisah, yaitu pada class
data context. Cara merupakan bagian dari Entity Framework, sehingga class data context
harus menggunakan namespace berikut ini.
using Microsoft.EntityFrameworkCore;
Fluent API mempunyai fitur konfigurasi yang lebih lengkap, selain memiliki fitur seperti yang
dimiliki oleh data annotation, fitur-fitur lainnya adalah:
1. Mendukung computed column atau kolom yang nilainya dihitung atau ditentukan
pada database.
2. Mendukung sequence.
3. Mendukung default value atau pemberian nilai default jika nilai suatu kolom tidak
diberikan.
4. Mendukung index.
5. Mendukung foreign key contraint yang digunakan untuk relasi antar model.
6. Mendukung lebih dari satu primary key.
Cara konfigurasi dengan menggunakan data annotations dan Fluent API akan dijelaskan dan
praktikkan pada sub bab berikutnya.
117
Keempat class ini akan disimpan pada folder Models. Berikut adalah isi kode lengkap dari
keempat class tersebut. Di bawah ini adalah kode lengkap class entity model Category.
Category.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
namespace SqlServerBookStore.Models
{
public partial class Category
{
public int CategoryID { set; get; }
public String Name { set; get; }
public ICollection<Book> Books { get; set; }
}
}
Class Category akan dibuat menjadi tabel dengan nama bentuk jamaknya yaitu Categories.
Jika ingin menentukan nama tabel sendiri maka perlu ditambahkan pada class data context.
Class ini memiliki 3 property yaitu:
- CategoryID, property ini adalah primary key. Dengan menambahkan “ID” di akhir
nama suatu property maka secara otomatis menjadikan primary key. Jika tipe data
yang digunakan untuk primary key adalah integer, maka secara otomatis nilainya
memiliki sifat auto increment.
- Name, property untuk menyimpan nilai nama kategori buku.
- Books, property ini tidak akan menjadi atribut pada tabel Categories. Property ini
berfungsi sebagai relasi dengan model Book yang akan dibuat setelah ini. Dengan
melihat property ini dapat diketahui jika sebuah object Category dapat digunakan
oleh banyak object Book.
Berikut adalah kode lengkap class entity model Book.
Book.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace SqlServerBookStore.Models
{
public partial class Book
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int BookID { set; get; }
public int CategoryID { set; get; }
public Category Category { get; set; }
public String Title { set; get; }
public String Photo { set; get; }
public DateTime PublishDate { set; get; }
public double Price { set; get; }
public int Quantity { set; get; }
public ICollection<BookAuthor> BooksAuthors { get; set; }
}
}
118
Class Book akan dibuat menjadi tabel dengan nama bentuk jamaknya yaitu Books. Class ini
memiliki property-property sebagai berikut:
- BookID, property ini adalah primary key dari tabel Books. Dapat dilihat di atas
property ini terdapat atribut [DatabaseGenerated(DatabaseGeneratedOption.None)],
atribut tersebut berfungsi agar nilai tidak menjadi auto increment. Sebagai informasi,
DatabaseGeneratedOption memiliki 3 opsi yaitu None, Identity dan Computed.
Untuk opsi Identity, nilai akan dibuat secara otomatis ketika data ditambahkan
pertama kali. Opsi ini cocok digunakan untuk property primary key. Opsi
Computed, nilai akan dibuat secara otomatis ketika data ditambahkan atau diupdate.
- CategoryID, property ini menjadi foreign key yang akan menyimpan nilai id dari
tabel Categories.
- Category, property ini tidak akan menjadi atribut pada tabel Book. Property ini
berfungsi sebagai relasi dengan model Category. Relasi yang terjadi dengan
membuat property CategoryID menjadi foreign key.
- Title, property untuk menyimpan judul buku.
- Photo, property untuk menyimpan nama file foto.
- PublishDate, property untuk menyimpan tanggal publish buku.
- Price, property untuk menyimpan harga buku.
- Quantity, property untuk menyimpan jumlah stok buku.
- BooksAuthors, property ini tidak akan menjadi atribut pada tabel Books. Property
ini berfungsi sebagai relasi dengan model BookAuthor yang akan dibuat setelah ini.
Dengan melihat property ini dapat diketahui jika sebuah object Book dapat
digunakan oleh banyak object BookAuthor.
Berikut adalah kode lengkap class entity model Author.
Author.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
namespace SqlServerBookStore.Models
{
public partial class Author
{
public int AuthorID { set; get; }
public String Name { set; get; }
public String Email { set; get; }
public ICollection<BookAuthor> BooksAuthors { get; set; }
}
}
Class Author akan dibuat menjadi tabel dengan nama bentuk jamaknya yaitu Authors. Class
ini memiliki property-property sebagai berikut:
- AuthorID, property ini adalah primary key dari tabel Authors.
- Name, property untuk menyimpan nama pengarang.
- Email, property untuk menyimpan email pengarang.
- BooksAuthors, property ini tidak akan menjadi atribut pada tabel Authors. Property
ini berfungsi sebagai relasi dengan model BookAuthor. Dengan melihat property ini
dapat diketahui jika sebuah object Author dapat digunakan oleh banyak object
BookAuthor.
119
Berikut ini adalah kode lengkap class BookAuthor.
BookAuthor.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
namespace SqlServerBookStore.Models
{
public partial class BookAuthor
{
public int BookAuthorID { set; get; }
public int BookID { set; get; }
public Book Book { get; set; }
public int AuthorID { set; get; }
public Author Author { get; set; }
}
}
Class BookAuthor akan dibuat menjadi tabel BooksAuthors, nama ini sesuai dengan nama
property BooksAuthor yang dimiliki oleh class Book dan class Author. Class ini memiliki
property-property sebagai berikut:
- BookAuthorID yang menjadi primary key.
- BookID, property ini menjadi foreign key yang akan menyimpan nilai id dari tabel
Books.
- Book, property ini tidak akan menjadi atribut pada tabel BooksAuthors. Property ini
berfungsi sebagai relasi dengan model Book. Relasi yang terjadi dengan membuat
property BookID menjadi foreign key.
- AuthorID, property ini menjadi foreign key yang akan menyimpan nilai id dari tabel
Authors.
- Author, property ini tidak akan menjadi atribut pada tabel BooksAuthors. Property
ini berfungsi sebagai relasi dengan model Author. Relasi yang terjadi dengan
membuat property AuthorID menjadi foreign key.
Dari keterangan di atas dapat dilihat jika model ini akan membuat tabel yang memiliki atribut
dengan sebuah primary key dan dua foreign key.
Class entity model yang lain adalah class turunan IdentityUser dan IdentityRole. Nama class
turunan tersebut adalah ApplicationUser dan ApplicationRole. Kedua class model ini untuk
mengelola data user dan role pada ASP.NET Core Identity. Keduanya telah dijelaskan pada
bab ASP.NET Core Identity.
Berikut adalah kode lengkap class ApplicationUser.cs
ApplicationUser.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
namespace SqlServerBookStore.Models
{
// Add profile data for application users by adding properties to the
ApplicationUser class
public class ApplicationUser : IdentityUser
120
{
public string FullName { get; set; }
public string Photo { get; set; }
}
}
Dari class di atas dapat dilihat class ApplicationUser akan memiliki property-property yang
dimiliki oleh class IdentityUser ditambah dengan property berikut ini:
- FullName, property untuk menyimpan nama lengkap dari user.
- Photo, property untuk menyimpan nama file foto beserta url lokasi penyimpanannya.
Berikut ini adalah kode lengkap class ApplicationRole.
ApplicationRole.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
namespace SqlServerBookStore.Models
{
public class ApplicationRole : IdentityRole
{
public string Description { get; set; }
}
}
Dari kode di atas dapat dilihat bahwa class ApplicationRole memiliki semua property yang
dimiliki oleh class IdentityRole ditambah dengan property Description yang berfungsi untuk
menyimpan keterangan dari role.
Selanjutnya adalah mendaftarkan class-class di atas ke dalam class data context. Pada project
SqlServerBookStore telah dimiliki class data context dengan nama ApplicationDbContext.cs
yang berada di dalam folder Data. Penambahan pada class ini merupakan syarat dari class
model agar dapat disebut sebagai class entity model.
Berikut adalah isi class ini setelah dimodifikasi.
ApplicationDbContext.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using SqlServerBookStore.Models;
namespace SqlServerBookStore.Data
{
public class ApplicationDbContext : IdentityDbContext<ApplicationUser,
ApplicationRole, string>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext>
options)
: base(options)
{
}
121
public virtual DbSet<Book> Books { get; set; }
public virtual DbSet<BookAuthor> BooksAuthors { get; set; }
Berikut adalah keterangan dari kode class di atas. Agar class-class pada folder Models dapat
dipanggil pada class ini maka perlu digunakan baris berikut ini.
using SqlServerBookStore.Models;
Pada kode di atas dapat dilihat cara pewarisan class IdentityDbContext dengan parameter
masukan berupa class ApplicationUser dan ApplicationRole.
Selanjutnya adalah membuat class entity model Category, Author, Book dan BookAuthor
dengan cara sebagai berikut.
public virtual DbSet<Category> Categories { get; set; }
public virtual DbSet<Author> Authors { get; set; }
public virtual DbSet<Book> Books { get; set; }
public virtual DbSet<BookAuthor> BooksAuthors { get; set; }
Dari kode di atas maka dapat dilihat untuk melakukan operasi database pada tabel
Categories, Authors Books dan BooksAuthors dapat dilakukan dengan menggunakan
keempat property tersebut.
122
Gambar 114. Book Store - Daftar buku.
Table BooksAuthors adalah table yang menyimpan relasi antara nama pengarang dan buku,
tetapi isinya hanya BookID dan AuthorID saja. Sehingga class BookAuthor juga tidak bisa
digunakan untuk menampilkan informasi seperti yang diinginkan di atas.
Untuk menampilkan informasti tersebut perlu digunakan sebuah model yang dapat
digunakan untuk menampung informasi dari 4 table sekaligus yaitu table Books,
BooksAuthors, Authors dan Categories.
Berikut ini adalah class view model yang akan digunakan untuk menampilkan data buku.
BookViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace SqlServerBookStore.Models
{
public partial class BookViewModel
{
public int ISBN { set; get; }
public String CategoryName { set; get; }
public String Title { set; get; }
public String Photo { set; get; }
public DateTime PublishDate { set; get; }
public double Price { set; get; }
public int Quantity { set; get; }
public string AuthorNames { set; get; }
}
}
Sebagai mana yang telah diketahui bahwa class entity model merupakan representasi sebuah
tabel pada database, sehingga harus didaftarkan pada class data context. Sedangkan class
view model bukan representasi dari tabel yang ada di database, sehingga class model ini tidak
perlu ditambahkan sebagai property pada class data context. Setelah class view model
menjadi object maka object ini hanya akan digunakan untuk menampung data yang didapat
object dari class entity model.
123
Berikut adalah kode lengkap bagaimana object dari class BookViewModel menampung data
dari object class entity model Author, Book dan Category. Kode ini adalah bagian dari class
controller BookController.cs. Pembahasan secara lengkap tentang komponen controller akan
dibahas pada sub bab Controller.
[HttpGet]
public IActionResult Index()
{
var bookList = db.Books
.Include(c => c.Category)
.Include(ba => ba.BooksAuthors)
.ThenInclude(a => a.Author)
.ToList();
item.ISBN = book.BookID;
item.Title = book.Title;
item.Photo = book.Photo;
item.PublishDate = book.PublishDate;
item.Price = book.Price;
item.Quantity = book.Quantity;
item.CategoryName = book.Category.Name;
items.Add(item);
}
return View(items);
}
Langkah pertama adalah mengambil daftar buku dari database dengan cara sebagai berikut.
var bookList = db.Books
.Include(c => c.Category)
.Include(ba => ba.BooksAuthors)
.ThenInclude(a => a.Author)
.ToList();
Langkah berikutnya adalah membuat object collection yang berisi dari object
BookViewModel.
Sekarang object bookList berisi daftar buku. Selanjutnya adalah mengisi object collection di
atas dengan object BookViewModel sehingga langkah pertama adalah melakukan
pengulangan sejumlah object yang berada di dalam object collection bookList. Kemudian
melakukan instansiasi class BookViewModel.
foreach(Book book in bookList){
BookViewModel item = new BookViewModel();
. . .
124
}
Selanjutnya mengisi object item dengan nilai-nilai dari object book dengan cara sebagai
berikut.
item.ISBN = book.BookID;
item.Title = book.Title;
item.Photo = book.Photo;
item.PublishDate = book.PublishDate;
item.Price = book.Price;
item.Quantity = book.Quantity;
Dari contoh di atas dapat dilihat object item sebagai instance class BooksViewModel telah
menampung data dari tabel Books. Selanjutnya adalah membaca tabel Categories untuk
mengambil nama kategori buku berdasarkan id dari kategori buku tersebut dengan cara
berikut ini.
item.CategoryName = book.Category.Name;
Karena daftar pengarang yang didapat pada tabel BooksAuthors hanya berisi id pengarang
saja maka perlu mengambil nama pengarang dengan cara berikut ini, kemudian menyimpan
nama-nama tersebut ke dalam variable authorNameList.
foreach(BookAuthor booksAuthors in booksAuthorsList){
var author = booksAuthors.Author;
authorNameList = authorNameList + author.Name + ", ";
}
item.AuthorNames = authorNameList.Substring(0, authorNameList.Length - 2);
items.Add(item);
Dan pada baris terakhir object item disimpan ke dalam object collection items. Maka sekarang
sudah didapat data buku yang lengkap, sehingga pada antarmuka dapat dilihat hasil seperti
pada gambar di atas.
Dari penjelasan dan contoh di atas dapat dilihat bahwa class view model tidak perlu
didaftarkan pada class data context, karena class ini tidak mewakili tabel pada database.
Penjelasan tentang cara melakukan query dan mengambil data dilakukan dengan .NET
Language-Integrated Query (LINQ). Pembahasan tentang LINQ akan dibahas lebih lanjut
pada sub bab Controller.
125
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
Dengan namespace ini maka cara memberian atribut menggunakan cara seperti berikut ini.
[Display(Name ="LABEL")]
using System.ComponentModel;
Dengan namespace ini maka cara pemberian atribut menggunakan cara seperti berikut ini.
[DisplayName("LABEL")]
Berikut ini adalah contoh penggunakan atribut ini pada class model Author dengan
menggunakan data annotation.
Author.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
namespace SqlServerBookStore.Models
{
public partial class Author
{
[Display(Name = "ID")]
public int AuthorID { set; get; }
[Display(Name = "Email")]
public String Email { set; get; }
}
}
126
Gambar 115. Display atribut model sebagai label pada header tabel.
Dengan menggunakan HTML Helper @Html.DisplayNameFor di halaman web pada
komponen view maka atribut pada komponen model ini bisa dipergunakan untuk
ditampilkan sebagai label pada header tabel seperti yang terlihat pada gambar di atas. Contoh
yang lain adalah penggunaan untuk form input.
Gambar 116. Display atribut model sebagai label pada form input.
Penjelasan tentang HTML Helper akan diberikan pada pada sub bab View.
Selain itu juga atribut DisplayFormat yang digunakan untuk melakukan format nilai property
saat ditampilkan pada halaman komponen view. Sintaks dari atribut ini adalah sebagai
berikut.
[DisplayFormat(DataFormatString = "{FORMAT}")]
127
public DateTime PublishDate {set; get;}
[DisplayFormat(DataFormatString = "{0:c}")]
public double Price {set; get;}
Relasi
Pada database relasional, umumnya terdapat relasi pada antar tabel. Sebagai contoh dapat
dilihat pada gambar di bawah ini.
Relasi One-to-Many
Berikut ini diberikan contoh dua class yang memiliki relasi one-to-many yaitu class Category
dan Book. Untuk menyatakan bahwa class Category dapat memiliki relasi dengan banyak
class Book, dapat dilihat pada baris yang dicetak tebal di bawah ini.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
namespace SqlServerBookStore.Models
{
public partial class Category
128
{
public int CategoryID { set; get; }
public String Name { set; get; }
public ICollection<Book> Books { get; set; }
}
}
Pada kode yang dicetak tebal di atas tersebut dibuat property Books dengan tipe
ICollection<Book>. Artinya property Books dapat menampung banyak object Book. Dengan
mengakses property ini maka akan didapat seluruh object Book dari sebuah object Category.
Di bawah ini adalah contoh class Book. Untuk menyatakan class ini memiliki relasi dengan
class Category dapat dilihat pada kode yang dicetak tebal.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace SqlServerBookStore.Models
{
public partial class Book
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int BookID { set; get; }
[ForeignKey("Category")]
public int CategoryID { set; get; }
Pada kode di atas dapat dilihat penggunaan atribut ForeignKey untuk menentukan agar
property CategoryID menjadi foreign key.
Kemudian dapat dilihat juga property Category dengan tipe dari class Category. Property ini
menyatakan bahwa sebuah object Book memiliki relasi kepada sebuah object Category.
Property ini juga dapat digunakan untuk mengakses object Category. Sehingga jika terdapat
object book1 yang dibuat dari class Book, maka untuk mengetahui nama kategori buku dapat
dilakukan dengan cara berikut ini.
book1.Category.Name
Selanjutnya contoh dan penggunaan relasi one-to-many akan dapat dilihat implementasinya
pada sub bab selanjutnya yaitu Book Store: Class Model & Atribut.
Relasi Many-to-Many
Untuk kasus relasi many-to-many dapat dilihat relasi seperti antara tabel books dan authors
seperti yang terlihat pada Gambar 86 di atas. Relasi ini membuat sebuah buku dapat ditulis
oleh banyak pengarang dan seorang pengarang dapat menulis banyak buku.
129
Implementasi relasi many-to-many dengan menggunakan class model akan dicontohkan
sebagai berikut. Sebagai contoh jika dimiliki class model Author dengan kode berikut ini.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
namespace SqlServerBookStore.Models
{
public partial class Author
{
public int AuthorID { set; get; }
public String Name { set; get; }
public String Email { set; get; }
namespace SqlServerBookStore.Models
{
public partial class Book
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int BookID { set; get; }
[ForeignKey("Category")]
public int CategoryID { set; get; }
public Category Category { get; set; }
public String Title { set; get; }
public String Photo { set; get; }
public DateTime PublishDate { set; get; }
public double Price { set; get; }
public int Quantity { set; get; }
Selanjutnya diperlukan class model tambahan untuk menyimpan relasi many-to-many ini
yaitu class BookAuthor berikut ini.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace SqlServerBookStore.Models
{
public partial class BookAuthor
{
130
public int BookAuthorID { set; get; }
[ForeignKey("Book")]
public int BookID { set; get; }
[ForeignKey("Author")]
public int AuthorID { set; get; }
}
}
Untuk membuat relasi class BookAuthor dengan class Book dibuat dapat dilihat pada tiga
baris pertama yang dicetak tebal. Sedangkan untuk membuat relasi dengan class Author
dapat dilihat pada baris selanjutnya yang dicetak tebal. Dengan kedua relasi ini maka relasi
many-to-many antara class Book dan Author telah dibuat.
Validasi
Model juga dapat memiliki atribut yang dapat digunakan untuk validasi pada halaman form.
Ada beberapa atribut yang dapat digunakan untuk proses validasi. Berikut adalah atribut-
atribut validasi yang dapat digunakan pada model, yaitu:
- Required.
- StringLength.
- DataType.
- MaxLength.
- MinLength.
- Range.
- RegularExpression.
- Compare.
Sintaks penulisan atribut-atribut validasi di atas adalah sebagai berikut.
Keterangan:
- AttributeName adalah nama atribut dari daftar di atas.
- param adalah nilai yang diperlukan oleh atribut untuk melakukan validasi. Nilai
param ini diperlukan untuk atribut seperti StringLength, untuk menentukan nilai
panjang dari string.
- message adalah pesan kesalahan yang akan ditampilkan jika nilai yang dimasukkan
tidak memenuhi kondisi validasi yang telah diberikan.
Seperti halnya atribut display yang telah dijelaskan pada sub bab sebelumnya, atribut validasi
ini juga ditulis di atas property dari class model. setiap property dapat memiliki atribut
validasi lebih dari satu.
[Display(Name ="Email")]
[Required(ErrorMessage = "Email harus diisi.")]
[StringLength(256, MinimumLength = 8, ErrorMessage = "Email harus memiliki m
aksimal 256 dan minimal 8 karakter.")]
131
public String Email {set; get;}
Sedangkan untuk mempermudah dan mempersingkat penulisan pesan kesalahan pada dapat
digunakan placeholder yaitu mempergunakan tanda { }. Berikut adalah nilai yang dapat
dipergunakan:
- 0, adalah nama property atau nama display.
- 1, adalah nilai parameter pertama.
- 2, adalah nilai parameter kedua.
Sehingga contoh di atas dapat ditulis dengan cara sebagai berikut ini.
[Display(Name ="Email")]
[Required(ErrorMessage = "{0} harus diisi.")]
[DataType(DataType.EmailAddress, ErrorMessage="{0} tidak valid." )]
[StringLength(256, MinimumLength = 8, ErrorMessage = "{0} harus memiliki mak
simal {1} dan minimal {2} karakter.")]
public String Email {set; get;}
Required
Atribut Required digunakan untuk memvalidasi property agar harus property harus diisi
dengan suatu nilai. Berikut adalah contoh penggunaan atribut ini.
[Display(Name ="Author's Name")]
[Required(ErrorMessage = "{0} harus diisi.")]
public String Name {set; get;}
Jika nilai property Name di atas tidak diisi saat proses input data pada form, maka akan
ditampilkan pesan kesalahan “Author's Name harus diisi.”.
StringLength
Atribut StringLength digunakan untuk memvalidasi property yang bernilai string. Atribut
ini akan memvalidasi agar jumlah karakter dari string yang diisikan tidak melebihi dari nilai
param. Berikut adalah conoth penggunaan atribut ini.
[StringLength(256, ErrorMessage = "{0} tidak boleh lebih {1} karakter.")]
public String Name {set; get;}
Pada contoh di atas dapat dilihat nilai param yang diberikan adalah 256, artinya jumlah
karakter yang dapat diberikan pada property Name tidak boleh lebih dari 256 karakter. Jika
nilai yang diberikan melewati jumlah itu maka akan ditampilkan pesan kesalahan “Author's
Name tidak boleh lebih 256 karakter.”.
Selain itu juga dapat diberikan parameter lain untuk menentukan jumlah karakter minimum
dengan cara sebagai berikut.
[StringLength(256, MinimumLength = 8, ErrorMessage = "{0} harus memiliki mak
simal {1} dan minimal {2} karakter.")]
Jika property class model menggunakan atribut di atas, maka jumlah karakter yang dapat
diberikan adalah maksimal 256 dan minimal tidak boleh kurang dari 8 karakter. Dan pesan
kesalahan yang akan ditampilkan adalah “Author’s Name harus memiliki maksimal 256 dan
minimal 8 karakter”.
DataType
Atribut DataType digunakan untuk memvalidasi property agar tipe nilai yang dimasukkan
sesuai dengan tipe data yang diberikan. Berikut adalah contoh penggunaan atribut ini.
132
[DataType(DataType.EmailAddress, ErrorMessage="{0} tidak valid." )]
public String Email {set; get;}
Untuk menentukan tipe data diguankan class static DataType. Ada beberapa nilai yang
dimiliki oleh class DataType yaitu:
- CreditCard.
- Currency.
- Data.
- DateTime.
- EmailAddress.
- Password.
- PhoneNumber.
- Dan lain-lain.
MaxLength
Atribut ini untuk membatasi jumlah karakter maksimal yang diberikan sebagai nilai property.
Berikut adalah contoh penggunaan atribut ini.
[MaxLength(256, ErrorMessage ="{0} tidak boleh lebih dari {1} karakter.")]
public String Email {set; get;}
Pesan kesalahan yang akan ditampilkan adalah “Email tidak boleh lebih dari 256 karakter”.
MinLength
Atribut ini untuk membatasi karakter minimal yang diberikan sebagai nilai property. Berikut
ini adalah contoh penggunaan atribut ini.
[MinLength(8, ErrorMessage = "{0} tidak boleh kurang dari {1} karakter.")]
public String Email {set; get;}
Pesan kesalahan yang akan ditampilkan adalah “Email tidak boleh kurang dari 8 karakter”.
Range
Atribut Range digunakan untuk membatasi nilai minimal dan maksimal nilai angka pada
suatu property. Berikut adalah contoh penggunaan atribut ini.
[Display(Name ="Harga")]
[Range(100, 10000, ErrorMessage = "{0} harus diantara Rp. {1} dan Rp. {2}")]
public decimal Price { get; set; }
Pesan kesalahan yang ditampilkan adalah sebagai berikut “Harga harus diantara Rp. 100 dan
Rp. 10000”.
Compare
Atribut Compare digunakan untuk membandingkan antara nilai-nilai dari dua property.
Sebagai contoh adalah membandingkan nilai property Password dan ConfirmPassword.
public string Password { get; set; }
Pesan kesalahan yang ditampilkan adalah sebagai berikut “Password dan ConfirmPassword
harus sama.”.
133
RegularExpression
Atribut ini digunakan untuk melakukan validasi nilai property dengan menggunakan pola
regular expression. Sebagai contoh untuk melakukan validasi email dapat digunakan contoh
sebagai berikut ini.
[RegularExpression(@"^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-
9]{2,4})+$", ErrorMessage = "{0} tidak valid.")]
public string Email { get; set; }
Category.cs
Class entity model Category ini akan digunakan pada komponen view untuk keperluan
menampilkan data, form menambah dan form mengedit data kategori buku. Class ini juga
digunakan pada komponen controller untuk proses menambah, mengambil, update dan
penghapusan data pada database.
Berikut adalah class entity model Category yang telah diberikan atribut-atribut untuk display
dan validasi.
Category.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
namespace SqlServerBookStore.Models
{
public partial class Category
{
[Display(Name = "ID")]
[Required(ErrorMessage = "{0} harus diisi.")]
public int CategoryID { set; get; }
Author.cs
Class entity model Author ini akan digunakan pada komponen view untuk keperluan
menampilkan data, menambah dan mengedit data pengarang buku. Class ini juga digunakan
pada komponen controller untuk proses menambah, mengambil, update dan penghapusan
data pada database.
134
Kode di bawah ini adalah kode lengkap class entity model Author yang telah diberikan
atribut-atribut untuk display dan validasi.
Author.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
namespace SqlServerBookStore.Models
{
public partial class Author
{
[Display(Name = "ID")]
[Required(ErrorMessage = "{0} harus diisi.")]
public int AuthorID { set; get; }
[Display(Name = "Email")]
[Required(ErrorMessage = "{0} harus diisi.")]
[StringLength(256, ErrorMessage = "{0} tidak boleh lebih {1}
karakter.")]
[RegularExpression(@"^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-
zA-Z0-9]{2,4})+$", ErrorMessage = "{0} tidak valid.")]
public String Email { set; get; }
Book.cs
Class entity model Book ini akan hanya akan digunakan pada komponen controller untuk
melakukan proses menambah, mengambil, update dan penghapusan data pada database.
Berikut ini adalah kode lengkap class entity model Book yang telah diberikan atribut-atribut
untuk display dan validasi.
Book.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace SqlServerBookStore.Models
{
public partial class Book{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Display(Name ="ISBN")]
[Required(ErrorMessage = "{0} harus diisi.")]
[RegularExpression("^[0-9]*$", ErrorMessage = "{0} harus angka")]
[StringLength(13, MinimumLength = 10, ErrorMessage = "{0} tidak
boleh lebih {1} dan tidak boleh kurang {2} karakter.")]
public int BookID {set; get;}
[ForeignKey("Category")]
135
[Display(Name ="Category ID")]
[Required(ErrorMessage = "{0} harus diisi.")]
[RegularExpression("^[0-9]*$", ErrorMessage = "{0} harus angka")]
public int CategoryID {set; get;}
[Display(Name ="Title")]
[Required(ErrorMessage = "{0} harus diisi.")]
public String Title {set; get;}
[Display(Name ="Photo")]
public String Photo {set; get;}
[Display(Name ="Price")]
[RegularExpression("^[0-9]*$", ErrorMessage = "{0} harus angka")]
public double Price {set; get;}
[Display(Name ="Quantity")]
[RegularExpression("^[0-9]*$", ErrorMessage = "{0} harus angka")]
public int Quantity {set; get;}
BookAuthor.cs
Class entity model BookAuthor ini akan hanya akan digunakan pada komponen controller
untuk melakukan proses menambah, mengambil, update dan penghapusan data pada
database. Class ini adalah class penghubung antara class Book dan Author.
Berikut adalah kode lengkap class entity model BookAuthor yang telah diberikan atribut-
atribut.
BookAuthor.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace SqlServerBookStore.Models
{
public partial class BookAuthor
{
public int BookAuthorID { set; get; }
[ForeignKey("Book")]
[Display(Name = "ISBN")]
[Required(ErrorMessage = "{0} harus diisi.")]
[RegularExpression("^[0-9]*$", ErrorMessage = "{0} harus angka")]
[StringLength(13, MinimumLength = 10, ErrorMessage = "{0} tidak
boleh lebih {1} dan tidak boleh kurang {2} karakter.")]
public int BookID { set; get; }
public Book Book { get; set; }
136
[ForeignKey("Author")]
[Display(Name = "AuthorID")]
[Required(ErrorMessage = "{0} harus diisi.")]
public int AuthorID { set; get; }
public Author Author { get; set; }
}
}
BookViewModel.cs
Class BookViewModel.cs adalah contoh dari implementasi class view model. Pada class ini
tidak diberikan atribut untuk validasi, karena class ini hanya digunakan untuk keperluan
menampilkan data saja. Class ini hanya akan digunakan pada komponen view Index.cshtml
untuk menampilkan data buku pada tabel.
Dan berikut ini adalah kode lengkap class view model BookViewModel.
BookViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
namespace SqlServerBookStore.Models
{
public partial class BookViewModel
{
[Display(Name = "ISBN")]
public int ISBN { set; get; }
[Display(Name = "Category")]
public String CategoryName { set; get; }
[Display(Name = "Title")]
public String Title { set; get; }
[Display(Name = "Photo")]
public String Photo { set; get; }
[Display(Name = "Price")]
[DisplayFormat(DataFormatString = "{0:c}")]
public double Price { set; get; }
[Display(Name = "Quantity")]
public int Quantity { set; get; }
137
BookFormViewModel.cs
Class BookFormViewModel.cs adalah contoh implementasi class view model. Class
BookFormViewModel.cs ini hanya akan digunakan pada komponen view Create.cshtml dan
Edit.cshtml. File komponen view Create.cshtml digunakan sebagai form untuk menambah
data buku. Sedangkan file komponen view Edit.cshtml digunakan sebagai form untuk
mengedit data buku.
Berikut adalah kode lengkap file class BookFormViewModel.cs.
BookFormViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Http;
namespace SqlServerBookStore.Models
{
public partial class BookFormViewModel
{
[Display(Name = "ISBN")]
public int ISBN { set; get; }
[Display(Name = "Category")]
public int CategoryID { set; get; }
[Display(Name = "Title")]
public String Title { set; get; }
[Display(Name = "Photo")]
[DataType(DataType.Upload)]
public IFormFile Photo { set; get; }
[Display(Name = "Price")]
[DataType(DataType.Currency)]
public double Price { set; get; }
[Display(Name = "Quantity")]
public int Quantity { set; get; }
Pada kode di atas dapat dilihat penggunakan interface IFormFile pada property Photo.
Interface ini merupakan bagian dari namespace Microsoft.AspNetCore.Http, sehingga jika
ingin menggunakan interface ini maka pada awal kode perlu ditambahkan namespace
tersebut, seperti yang dapat dilihat pada contoh di atas. Interface IFormFile digunakan untuk
keperluan upload file, pada kasus ini ada keperluan untuk mengupload file gambar cover
buku.
138
RoleViewModel.cs
Class RoleViewModel adalah class view model yang digunakan untuk pada komponen view
Index.cshtml, Create.cshtml dan Edit.cshtml. Sehingga class tersebut dapat digunakan untuk
menampilkan daftar role, menambah dan mengedit data role.
Berikut ini adalah kode lengkap class entity model RoleViewModel yang telah diberikan
atribut-atribut untuk display dan validasi.
RoleViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
namespace SqlServerBookStore.Models
{
public partial class RoleViewModel
{
[Display(Name = "Role ID")]
[Required(ErrorMessage = "{0} harus diisi.")]
public string RoleID { get; set; }
[Display(Name = "Description")]
[Required(ErrorMessage = "{0} harus diisi.")]
public string Description { set; get; }
}
}
UserViewModel.cs
Class UserViewModel adalah class view model yang digunakan pada komponen view
Index.cshtml. Class ini berfungsi untuk menampilkan daftar user.
Berikut ini adalah kode lengkap class entity model UserViewModel yang telah diberikan
atribut-atribut untuk display. Class ini tidak memerlukan atribut-atribut untuk validasi
karena hanya digunakan untuk menampilkan data.
UserViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
namespace SqlServerBookStore.Models
{
public partial class UserViewModel
{
[Display(Name = "Username")]
public String UserName { set; get; }
[Display(Name = "Role")]
public String RoleName { set; get; }
[Display(Name = "Email")]
139
public String Email { set; get; }
[Display(Name = "Fullname")]
public String FullName { set; get; }
}
}
UserCreateFormViewModel.cs
Class UserCreateViewModel adalah class view model yang digunakan pada komponen view
Create.cshtml. Class ini berfungsi untuk menambah data user.
Berikut ini adalah kode lengkap class entity model UserCreateViewModel yang telah
diberikan atribut-atribut untuk display dan validasi.
UserCreateFormViewModel.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace SqlServerBookStore.Models
{
public partial class UserCreateFormViewModel{
[Display(Name ="Username")]
[Required(ErrorMessage = "{0} harus diisi.")]
public String UserName {set; get;}
[Display(Name ="Role")]
[Required(ErrorMessage = "{0} harus diisi.")]
public string[] RoleID {set; get;}
[Display(Name ="Email")]
[Required(ErrorMessage = "{0} harus diisi.")]
[StringLength(256, ErrorMessage = "{0} tidak boleh lebih {1}
karakter.")]
[RegularExpression(@"^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-
zA-Z0-9]{2,4})+$", ErrorMessage = "{0} tidak valid.")]
public String Email {set; get;}
[Display(Name ="Password")]
[Required(ErrorMessage = "{0} harus diisi.")]
[StringLength(256, ErrorMessage = "{0} tidak boleh lebih {1}
karakter.")]
[DataType(DataType.Password)]
public String Password {set; get;}
140
UserEditFormViewModel.cs
Class UserEditViewModel adalah class view model yang digunakan pada komponen view
Edit.cshtml. Class ini berfungsi untuk mengedit informasi user yang dipilih.
Berikut ini adalah kode lengkap class entity model UserEditViewModel yang telah diberikan
atribut-atribut untuk display dan validasi.
UserEditFormViewModel.cs
using System;
using System.ComponentModel.DataAnnotations;
namespace SqlServerBookStore.Models
{
public partial class UserEditFormViewModel{
[Display(Name ="Username")]
[Required(ErrorMessage = "{0} harus diisi.")]
public String UserName {set; get;}
[Display(Name ="Role")]
[Required(ErrorMessage = "{0} harus diisi.")]
public string[] RoleID {set; get;}
[Display(Name ="Email")]
[Required(ErrorMessage = "{0} harus diisi.")]
[StringLength(256, ErrorMessage = "{0} tidak boleh lebih {1}
karakter.")]
[RegularExpression(@"^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-
zA-Z0-9]{2,4})+$", ErrorMessage = "{0} tidak valid.")]
public String Email {set; get;}
Berbeda dengan class UserCreateFormViewModel, class ini tidak memiliki atribut Password
dan PasswordConfirm. Sehingga tidak dimungkinkan untuk mengedit atau mengubah
password user yang dipilih pada halaman ini. Hal ini dikarenakan ASP.NET Core Identity
hanya memberikan prosedur menganti password dengan cara dilakukan oleh user sendiri,
kemudian sistem akan mengirimkan kode ke email user tersebut. Selanjutnya email tersebut
dapat digunakan untuk mengubah atau reset password.
ApplicationUser.cs
Class ApplicationUser digunakan untuk manambah atribut pada class IdentityUser. Tidak
ada atribut display dan validasi yang ditambahkan pada class ini, karena proses
menampilkan daftar user, menambah dan mengedit data digunakan class view model yang
telah disebutkan di atas.
Berikut ini adalah kode lengkap dari class ApplicationUser.
ApplicationUser.cs
using System;
using System.Collections.Generic;
using System.Linq;
141
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
namespace SqlServerBookStore.Models
{
// Add profile data for application users by adding properties to the
ApplicationUser class
public class ApplicationUser : IdentityUser
{
public string FullName { get; set; }
public string Photo { get; set; }
}
}
ApplicationRole.cs
Class ApplicationRole digunakan untuk manambah atribut pada class IdentityRole. Tidak
ada atribut display dan validasi yang ditambahkan pada class ini, karena proses
menampilkan daftar user, menambah dan mengedit data digunakan class view model yang
telah disebutkan di atas.
Berikut ini adalah kode lengkap dari class ApplicationRole.
ApplicationRole.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
namespace SqlServerBookStore.Models
{
public class ApplicationRole : IdentityRole
{
public string Description { get; set; }
}
}
Startup.cs
Sebelum membuat class migrations yang baru, pastikan class Startup.cs telah dimodifikasi
seperti berikut ini.
Startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
142
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using SqlServerBookStore.Data;
using SqlServerBookStore.Models;
using SqlServerBookStore.Services;
namespace SqlServerBookStore
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
// This method gets called by the runtime. Use this method to add
services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))
);
services.AddMvc();
}
143
app.UseStaticFiles();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
Migrations Code
Selanjutnya untuk membuat class migrations yang baru maka terlebih dahulu folder
Migrations dan isinya harus dihapus. Selanjutnya buka Package Manager Console dan
ketikan perintah berikut ini.
Add-Migration InitialCreate
Hasilnya dapat dilihat pada folder Migrations seperti pada gambar di bawah ini.
Hasil perintah ini akan dapat dilihat pada folder Migrations berupa file:
- *_InitialCreate.cs
- *_InitialCreate.Designer.cs
- ApplicationDbContextModelSnapshot.cs.
Dimana tanda “*” adalah timestamp saat kedua file tersebut dibuat. Sebagai contoh pada
kode yang penulis buat memiliki nama file sebagai berikut:
- 20180314132028_InitialCreate.cs.
- 20180314132028_ InitialCreate.Designer.cs.
144
Update Database
Selanjutnya adalah menjalankan perintah ini untuk membuat database dan tabel-tabel sesuai
dengan class-class model yang telah dibuat.
Update-Database
Hasilnya database dan table-table telah dibuat seperti yang terlihat pada gambar di bawah
ini.
Controller
Controller adalah komponen yang menangani interaksi user, menentukan view yang akan
ditampilkan dan menghubungkan dengan model. Sebagai contoh, user dapat berinteraksi
dengan controller dengan cara menulis nama controller dan aksi yang diinginkan pada
address bar di web browser, kemudian respon dengan memilihkan view yang akan
ditampilkan sesuai dengan aksi yang telah dipanggil. Sebelum memilihkan view yg akan
ditampilkan, aksi pada controller dapat berisi logika yang berisi baris perintah seperti
perintah untuk melakukan pengambilan data ke database kemudian data akan dimasukkan
ke dalam collection yang berisi object model, dan kemudian menampilkannya pada view
yang diinginkan. Aksi pada controller juga dapat berisi logika untuk menangani proses
upload file dan logika-logika lainnya.
Implementasi komponen controller pada ASP.NET Core MVC adalah berupa class controller.
Class ini memiliki beberapa aturan, yaitu aturan penamaan dan penulisan program. Untuk
penamaan class controller digunakan aturan sebagai berikut.
{ControllerName}Controller.cs
145
Jika ControllerName adalah Categories maka nama file yang harus digunakan adalah
CategoriesController.cs. Contoh lain, jika nama controller adalah Books maka nama file yang
harus digunakan adalah BooksController.cs.
Untuk aturan penulisan program adalah sebagai berikut.
using System.Linq;
using Microsoft.AspNetCore.Mvc;
namespace {NameSpace}
{
public class {ControllerName}Controller : Controller
{
. . .
}
}
Keterangan:
- {NameSpace} adalah name namespace yang biasanya sesuai dengan nama folder
tempat menyimpan file class controller ini.
- {ControllerName} adalah nama controller seperti yang dicontohkan pada aturan
penamaan di atas.
Selanjutnya di dalam class ini akan berisi method-method seperti umumnya sebuah class.
Untuk method yang dapat diakses oleh komponen view maka method tersebut harus
mengikuti aturan sebagai method action.
Berikut ini adalah aturan penulisan program method action.
[Attribute]
public IActionResult MethodName()
{
. . .
return View();
}
Keterangan:
- Sebuah method action menggunakan interface IActionResult yang berfungsi
sebagai tipe keluaran dari method tersebut. Pada contoh di atas dapat dilihat
bahwa method action mengembalikan keluaran.
- Pada sebuah action dapat diberikan atribut dengan cara penulisan seperti di atas.
Salah manfaat atribut adalah dapat memberikan hak akses pada method action.
Atribut yang umum sering digunakan pada method action adalah penggunaan atribut berikut
ini:
- HttpGet, atribut ini untuk menyatakan bahwa pengiriman data akan dilakukan
dengan method GET.
- HttpPost, atribut ini untuk menyatakan bahwa pengiriman data akan dilakukan
dengan method POST.
Untuk pengembangan aplikasi web Book Store yang terdiri atas 3 fitur maka untuk masing-
masing fitur dapat ditangani oleh 3 komponen controller. Oleh karena itu perlu dibuat 3 file
class controller yaitu:
- CategoriesController.cs.
- AuthorsController.cs.
- BooksController.cs.
146
View Bag
ASP.NET Core MVC memiliki sarana yang dapat digunakan untuk melakukan pertukaran
data antara controller dan view yaitu ViewBag. Object ini sangat membantu untuk
melakukan komunikasi pada sisi server antara controller dan view. View bag dapat
menampung nilai primitif seperti bilangan atau string. Selain itu view bag juga dapat
menampung object atau kumpulan object yang disimpan pada sebuah collection.
Setelah view bag memiliki nilai selanjutnya nilai tersebut dapat ditampilkan secara langsung
pada halaman web sebagai teks atau ditampilkan secara tidak langsung sebagai item pada
elemen <select>.
Siklus hidup dari object ini singkat, sehingga valuenya akan bernilai null jika terjadi proses
redirect halaman.
Untuk latihan digunakan class controller LatihanController.cs yang telah dibuat pada sub bab
sebelumnya. Kemudian pada tambahkan method action LatihanViewBag, selanjutnya
tambahkan file LatihanViewBag.cshtml pada folder Views/Latihan.
[HttpGet]
public IActionResult LatihanViewBag()
{
return View();
}
Contoh pertama pengguan view bag adalah untuk menampilkan nilai statik yaitu untuk
menampilkan nilai variable bertipe integer dan string. Sehingga kode method action di atas
menjadi sebagai berikut ini.
public IActionResult LatihanViewBag()
{
ViewBag.VariableInt = 13;
ViewBag.VariableString = "ASP.NET Core MVC";
return View();
}
Dari contoh di atas maka dapat dilihat sintaks penggunaan object view bag adalah sebagai
berikut.
ViewBag.NAMA_PROPERTY = NILAI;
Untuk menampilkan object view bag pada halaman komponen view dapat dilakukan dengan
menggunakan sintaks Razor berikut ini.
@ViewBag.NAMA_PROPERTY
LINQ
LINQ atau .NET Language-Integrated Query adalah fitur yang dimililiki oleh bahasa
pemrograman pada lingkungan .NET. Fitur ini memungkinkan untuk melakukan query pada
sintaks di dalam bahasa pemrograman yang digunakan. Query dapat dilakukan pada object
bertipe array, enumerable class, dokumen XML dan database.
147
Pada sub bab ASP.NET Core MVC & MySQL telah diberikan contoh integrasi Entity
Framework Core sebagai framework data access pada aplikasi web ASP.NET Core MVC.
Pada contoh tersebut juga dapat dilihat implementasi LINQ untuk melakukan query
database.
Penggunaan LINQ dapat dilakukan dengan dua cara yaitu dengan cara Extension Method
dan penulisan kode query seperti query yang umum digunakan pada SQL. Pada sub bab
sebelumnya diberikan contoh penggunaan LINQ dengan menggunakan extension method.
Pada sub bab ini akan diperlihakan contoh dan penjelasan implementasi LINQ untuk
mendukung pembangunan aplikasi web book store.
Sumber Data
Seperti yang disebutkan di atas bahwa query dapat dilakukan pada sumber data salah
satunya adalah database. Dengan menggunakan Entity Framework sebagai framework data
access maka setiap tabel dapat di akses dalam bentuk object DbSet. Pada class
BookStoreDataContext.cs dapat dilihat bahwa class ini memiliki 4 property dengan tipe
DbSet, yaitu:
- Categories.
- Authors.
- Books.
- BooksAuthors.
Jika dibuat instansiasi object dari class BookStoreDataContext dengan cara berikut ini.
Maka akan dimiliki 4 sumber data yang dapat diakses dengan cara berikut ini.
db.Categories
db.Authors
db.Books
db.BooksAuthors
Setiap property di atas menyimpan data dari tabel category, author, book dan book_author.
NamaMethod(namaObject)
Dari cara di atas dapat dilihat pada method dapat diisi suatu object atau suatu nilai yang akan
diproses oleh method. Sedangkan cara penulisan extension method adalah sebagai berikut.
namaObject.NamaMethod()
148
Untuk mengambil data digunakan method Select, sehingga untuk mengambil dapat
dilakukan dengan cara berikut ini.
Dari contoh di atas, db.Authors dapat dianalogikan sebagai namaObject. Sedangkan method
Select(p => p) dapat dianalogikan sebagai method NamaMethod(). Tetapi didalam method
Select() dapat dilihat expression yang dikenal dengan nama lambda expression. Sintaks dari
lambda expression dapat dilihat di bawah ini.
input_parameter => expression_atau_statement
Keterangan:
- input_parameter adalah input.
- => adalah operator lambda.
- expression_atau_statement adalah expression atau statement yang menjadi
output.
Sehingga p => p dapat diartikan seluruh input p akan menjadi output. Contoh lain adalah x
=> 2 * x, artinya adalah terdapat input x dan ouput 2 * x. Sedangkan untuk untuk contoh kasus
penggunaan extension method Select() di atas, input p berisi nilai dari db.Authors.
Sedangkan yang menjadi ouput adalah seluruh p. Dan output p akan disimpan ke object
items yang berisi kumpulan atau lebih dari satu object Category.
Untuk melakukan filter data digunakan method Where. Berikut adalah contoh melakukan
filter dengan method ini.
Pada contoh di atas dapat dilihat input p berisi nilai dari db.BooksAuthors, sedangkan yang
menjadi ouput adalah object p yang memiliki nilai property ISBN yang sama dengan nilai
book.ISBN. Output p akan disimpan ke dalam object items. Object items akan berisi
kumpulan object atau lebih dari satu object BookAuthor.
Untuk mendapatkan sebuah object saja, maka dapat dilakukan filter dengan menggunakan
property class yang berperan sebagai primary key. Berikut ini contoh dari solusi kasus
tersebut.
Method SingleOrDefault digunakan untuk mendapatkan sebuah object. Pada kasus di atas
sebuah object Category didapat dengan cara melakukan filter berdasarkan property
CategoryID.
Ketiga contoh di atas adalah contoh penggunaan extension method. Ketiga contoh di atas
dapat ditulis dengan style sintaks SQL dengan sedikit perbedaan. Untuk contoh pertama di
atas dapat ditulis menjadi berikut ini.
Jika pada sintaks SQL dimulai dengan keyword “select” kemudian diikuti “from” untuk
menentukan sumber datanya. Tetapi dengan LINQ, hal pertama yang dilakukan adalah
memilih sumber data dengan keyword “from” dalam kasus di atas sumber datanya adalah
149
db.Categories, kemudian baru digunakan keyword “select” untuk memilih property apa saja
yang ingin diambil atau ditampilkan.
Sedangkan untuk contoh kedua di atas dapat ditulis sebagai berikut.
Dari penjelasan di atas dapat dilihat bagaimana query menjadi bagian dari bahasa
pemrograman pada lingkungan .NET. Masih banyak sintaks query yang dimiliki oleh LINQ
seperti layaknya sintaks SQL yang dapat dilihat pada link berikut ini
https://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b.
Keterangan:
- db adalah object dari class data context.
- obj adalah object dari class entity model.
Untuk operasi edit data digunakan sintaks berikut ini.
db.Update(obj);
db.SaveChanges();
Keterangan:
- DbSetObject adalah object class DbSet yang didaftarkan sebagai property dari
class data context. Dalam kasus ini adalah class BookStoreDataContext.cs.
Sehingga jika ingin menghapus data dari tabel category maka digunakan kode berikut ini.
db.Categories.Remove(item);
db.SaveChanges();
150
komponen controller yang dibuat. Tetapi akan ada modifikasi terhadap class-class controller
yang digenerate itu untuk menyesuaikan dengan antarmuka dan class model yang telah
disiapkan. Class tersebut adalah class BooksController.
Selain itu ada juga class controller yang tidak dapat dibuat secara otomatis seperti class
controller untuk mengelola role dan user. Hal ini disebabkan data role dan user dikelola
dengan menggunakan ASP.NET Core Identity.
151
Gambar 121. CategoriesController - Window Add MVC Controller with views, using
Entity Framework.
Berikut adalah nilai-nilai yang harus dipilih dan diisi, yaitu:
- Model class, pilih komponen model Category.
- Data context class, pilih ApplicationDbContext.
Setelah tombol Add diklik maka hasilnya dapat dilihat pada file CategoriesController.cs di
dalam folder Controllers. Berikut adalah isi dari file tersebut.
CategoriesController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using SqlServerBookStore.Data;
using SqlServerBookStore.Models;
namespace SqlServerBookStore.Controllers
{
public class CategoriesController : Controller
{
private readonly ApplicationDbContext _context;
// GET: Categories
public async Task<IActionResult> Index()
{
return View(await _context.Categories.ToListAsync());
}
// GET: Categories/Details/5
public async Task<IActionResult> Details(int? id)
152
{
if (id == null)
{
return NotFound();
}
return View(category);
}
// GET: Categories/Create
public IActionResult Create()
{
return View();
}
// POST: Categories/Create
// To protect from overposting attacks, please enable the specific
properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("CategoryID,Name")]
Category category)
{
if (ModelState.IsValid)
{
_context.Add(category);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(category);
}
// GET: Categories/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
// POST: Categories/Edit/5
// To protect from overposting attacks, please enable the specific
properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
153
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id,
[Bind("CategoryID,Name")] Category category)
{
if (id != category.CategoryID)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(category);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!CategoryExists(category.CategoryID))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(category);
}
// GET: Categories/Delete/5
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}
return View(category);
}
// POST: Categories/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
var category = await _context.Categories.SingleOrDefaultAsync(m
=> m.CategoryID == id);
_context.Categories.Remove(category);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
154
}
Selanjutnya adalah melakukan koneksi ke database dengan memanfaatkan class data context
ApplicationDbContext. Caranya adalah dengan membuat object dari class tersebut seperti
yang dapat dilihat pada kode berikut ini.
private readonly ApplicationDbContext _context;
Dari kode di atas, object _context dapat digunakan untuk melakukan operasi ke database
pada method action.
Pada class controller ini terdapat 8 method action, yaitu:
- [HttpGet]Index.
- [HttpGet]Details.
- [HttpGet]Create.
- [HttpPost]Create.
- [HttpGet]Edit.
- [HttpPost]Edit.
- [HttpGet]Delete.
- [HttpPost]Delete.
Pada kode di atas dilakukan pengiriman data ke komponen view dengan cara berikut ini.
155
return View(DATA)
Isi dari DATA adalah data Category, untuk mengambil data dapat dilakukan dengan cara
berikut ini.
_context.Categories.ToListAsync()
Komponen view dari method action Index ini adalah file Views/Categories/Index.cshtml.
return View(category);
}
Pada awal kode di atas dapat dilihat URL untuk menentukan nilai id dari data yang dipilih.
Kemudian data dapat diambil dari database dengan cara berikut ini.
var category = await _context.Categories
.SingleOrDefaultAsync(m => m.CategoryID == id);
Data akan disimpan pada object category yang selanjutkan akan dikirimkan ke komponen
view dengan cara berikut.
return View(category);
Komponen view dari method action Details ini adalah file Views/Categories/Details.cshtml.
156
Komponen view dari method action Create ini adalah file Views/Categories/Create.cshtml.
Untuk mengirimkan data dari form umumnya digunakan method POST, sehingga method
ini memiliki atribut [HttpPost]. Dan untuk mengamankan pemalsuan pengiriman data
digunakan atribut [ValidateAntiForgeryToken].
Input untuk method ini adalah data yang dikirimkan dari komponen view, hal ini dapat
dilihat pada parameter pada method ini.
Selanjutnya data akan ditambahkan dan disimpan dengan cara berikut ini.
_context.Add(category);
await _context.SaveChangesAsync();
Jika proses penyimpan berhasil maka akan ditampilkan daftar data dengan cara mengkases
komponen view Index.
return RedirectToAction(nameof(Index));
Jika proses penyimpanan gagal maka pengguna akan tetap berada pada halaman form input
dan akan ditampilkan pesan kesalahan.
157
if (category == null)
{
return NotFound();
}
return View(category);
}
Data yang dipilih disimpan pada objek category. Kemudian untuk mengirimkan data ke
komponen view digunakan kode berikut.
return View(category);
Komponen view dari method action Index ini adalah file Views/Categories/Edit.cshtml.
if (ModelState.IsValid)
{
try
{
_context.Update(category);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!CategoryExists(category.CategoryID))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(category);
}
Cara kerja kode di atas mirip dengan cara kerja method action [HttpPost]Create. Yang
membedakan adalah kode berikut ini.
_context.Update(category);
await _context.SaveChangesAsync();
158
Kode di atas adalah kode untuk mengupdate data.
return View(category);
}
Komponen view dari method action Index ini adalah file Views/Categories/Delete.cshtml.
Nama method di atas adalah DeleteConfirmed, tetapi pada implementasinya akan dipanggil
dengan nama Delete. Hal ini dapat dilihat dengan penggunaan atribut berikut.
[HttpPost, ActionName("Delete")]
Kemudian data yang akan dihapus ditampung terlebih dahulu dengan cara berikut.
var category = await _context.Categories.SingleOrDefaultAsync(m =>
m.CategoryID == id);
Dan untuk menampus data dari database digunakan kode berikut ini.
_context.Categories.Remove(category);
await _context.SaveChangesAsync();
159
Class Controller Authors
Untuk fitur pengelolaan pengarang buku dapat digunakan untuk:
- Menampilkan daftar pengarang buku.
- Menampilkan daftar pengarang buku yang dipilih.
- Menambah data pengarang buku.
Untuk menambah data pengarang buku terlebih dahulu perlu ditampilkan form
input pengarang buku. Kemudian pengguna akan mengisi form input tersebut
dan setelah tombol submit diklik akan dilakukan proses menyimpanan data yang
dimasukkan ke dalam database.
- Mengedit data pengarang buku yang dipilih.
Untuk mengedit data pengarang buku terlebih dahulu perlu ditampilkan form
input edit pengarang buku. Kemudian pengguna akan mengedit data dari form
edit. Setelah tombol submit diklik maka dilakukan proses update data ke dalam
database.
- Menghapus data pengarang buku yang dipilih.
Komponen controller untuk mengelola data Author akan memiliki nama dalam bentuk jamak
yaitu Authors. Berikut ini adalah langkah-langkah untuk membuat class controller ini.
Langkah pertama klik kanan pada folder Controllers kemudian piliha Add > Controller. Pada
window Add Scaffold pilih MVC Controller with views, using Entity Framework.
160
Gambar 123. AuthorsController - Window Add MVC Controller with views, using
Entity Framework.
Berikut adalah nilai-nilai yang harus dipilih dan diisi, yaitu:
- Model class, pilih komponen model Author.
- Data context class, pilih ApplicationDbContext.
Setelah tombol Add diklik maka hasilnya dapat dilihat pada file AuthorsController.cs di
dalam folder Controllers. Berikut adalah isi dari file tersebut.
AuthorsController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using SqlServerBookStore.Data;
using SqlServerBookStore.Models;
namespace SqlServerBookStore.Controllers
{
public class AuthorsController : Controller
{
private readonly ApplicationDbContext _context;
// GET: Authors
public async Task<IActionResult> Index()
{
return View(await _context.Authors.ToListAsync());
}
// GET: Authors/Details/5
public async Task<IActionResult> Details(int? id)
161
{
if (id == null)
{
return NotFound();
}
return View(author);
}
// GET: Authors/Create
public IActionResult Create()
{
return View();
}
// POST: Authors/Create
// To protect from overposting attacks, please enable the specific
properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult>
Create([Bind("AuthorID,Name,Email")] Author author)
{
if (ModelState.IsValid)
{
_context.Add(author);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(author);
}
// GET: Authors/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
// POST: Authors/Edit/5
// To protect from overposting attacks, please enable the specific
properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
162
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id,
[Bind("AuthorID,Name,Email")] Author author)
{
if (id != author.AuthorID)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(author);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!AuthorExists(author.AuthorID))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(author);
}
// GET: Authors/Delete/5
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}
return View(author);
}
// POST: Authors/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
var author = await _context.Authors.SingleOrDefaultAsync(m =>
m.AuthorID == id);
_context.Authors.Remove(author);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
163
}
Selanjutnya adalah melakukan koneksi ke database dengan memanfaatkan class data context
ApplicationDbContext. Caranya adalah dengan membuat object dari class tersebut seperti
yang dapat dilihat pada kode berikut ini.
private readonly ApplicationDbContext _context;
Dari kode di atas, object _context dapat digunakan untuk melakukan operasi ke database
pada method action.
Pada class controller ini terdapat 8 method action, yaitu:
- [HttpGet]Index.
- [HttpGet]Details.
- [HttpGet]Create.
- [HttpPost]Create.
- [HttpGet]Edit.
- [HttpPost]Edit.
- [HttpGet]Delete.
- [HttpPost]Delete.
Pada kode di atas dilakukan pengiriman data ke komponen view dengan cara berikut ini.
164
return View(DATA)
Isi dari DATA adalah data Author, untuk mengambil data dapat dilakukan dengan cara
berikut ini.
_context.Authors.ToListAsync()
Komponen view dari method action Index ini adalah file Views/Authors/Index.cshtml.
return View(author);
}
Pada awal kode di atas dapat dilihat URL untuk menentukan nilai id dari data yang dipilih.
Kemudian data dapat diambil dari database dengan cara berikut ini.
var author = await _context.Authors
.SingleOrDefaultAsync(m => m.AuthorID == id);
Data akan disimpan pada object author yang selanjutkan akan dikirimkan ke komponen view
dengan cara berikut.
return View(author);
Komponen view dari method action Details ini adalah file Views/Authors/Details.cshtml.
Komponen view dari method action Create ini adalah file Views/Authors/Create.cshtml.
165
Method Action [HttpPost]Create
Setelah data diisi pada form input yang ditampilkan oleh method action di atas maka proses
selanjutnya adalah menyimpan data.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("AuthorID,Name,Email")] Author
author)
{
if (ModelState.IsValid)
{
_context.Add(author);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(author);
}
Untuk mengirimkan data dari form umumnya digunakan method POST, sehingga method
ini memiliki atribut [HttpPost]. Dan untuk mengamankan pemalsuan pengiriman data
digunakan atribut [ValidateAntiForgeryToken].
Input untuk method ini adalah data yang dikirimkan dari komponen view, hal ini dapat
dilihat pada parameter pada method ini.
Selanjutnya data akan ditambahkan dan disimpan dengan cara berikut ini.
_context.Add(author);
await _context.SaveChangesAsync();
Jika proses penyimpan berhasil maka akan ditampilkan daftar data dengan cara mengkases
komponen view Index.
return RedirectToAction(nameof(Index));
Jika proses penyimpanan gagal maka pengguna akan tetap berada pada halaman form input
dan akan ditampilkan pesan kesalahan.
166
return NotFound();
}
return View(author);
}
Data yang dipilih disimpan pada objek author. Kemudian untuk mengirimkan data ke
komponen view digunakan kode berikut.
return View(author);
Komponen view dari method action Index ini adalah file Views/Authors/Edit.cshtml.
if (ModelState.IsValid)
{
try
{
_context.Update(author);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!AuthorExists(author.AuthorID))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(author);
}
Cara kerja kode di atas mirip dengan cara kerja method action [HttpPost]Create. Yang
membedakan adalah kode berikut ini.
_context.Update(author);
await _context.SaveChangesAsync();
167
Method Action [HttpGet]Delete
Method action ini bertujuan sebagai konfirmasi sebelum data dihapus. Data yang akan
dihapus akan ditampilkan terlebih dahulu seperti menampilkan detail data seperti yang
dilakukan oleh method action [HttpGet]Details. Berikut adalah kode dari method action ini.
// GET: Authors/Delete/5
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}
return View(author);
}
Komponen view dari method action Index ini adalah file Views/Authors/Delete.cshtml.
Nama method di atas adalah DeleteConfirmed, tetapi pada implementasinya akan dipanggil
dengan nama Delete. Hal ini dapat dilihat dengan penggunaan atribut berikut.
[HttpPost, ActionName("Delete")]
Kemudian data yang akan dihapus ditampung terlebih dahulu dengan cara berikut.
var author = await _context.Authors.SingleOrDefaultAsync(m => m.AuthorID ==
id);
Dan untuk menampus data dari database digunakan kode berikut ini.
_context.Authors.Remove(author);
await _context.SaveChangesAsync();
168
- Menampilkan daftar buku.
- Menampilkan detail buku yang dipilih.
- Menambah data buku.
Untuk menambah data buku terlebih dahulu perlu ditampilkan form input buku.
Kemudian pengguna akan mengisi form input tersebut dan setelah tombol
submit diklik akan dilakukan proses menyimpanan data yang dimasukkan ke
dalam database.
- Mengedit data buku yang dipilih.
Untuk mengedit data buku terlebih dahulu perlu ditampilkan form input edit
buku. Kemudian pengguna akan mengedit data dari form edit. Setelah tombol
submit diklik maka dilakukan proses update data ke dalam database.
- Menghapus data buku yang dipilih.
Maka langkah pertama adalah akan dibuat komponen controller dan view dengan cara
berikut ini.
Klik kanan pada folder Controllers, kemudian pilih Add > Controller. Kemudian pada
window Add Scaffold, pilih MVC Controller with views, using Entity Framework. Setelah itu
ditampilkan window Add MVC Controller with views, using Entity Framework seperti pada
gambar di bawah ini.
Gambar 124. BooksController - Window Add MVC Controller with views, using
Entity Framework.
Berikut adalah nilai-nilai yang harus dipilih dan diisi, yaitu:
- Model class, pilih komponen model Book.
- Data context class, pilih ApplicationDbContext.
Setelah tombol Add diklik maka hasilnya dapat dilihat pada file BooksController.cs di dalam
folder Controllers. Berikut adalah isi dari file tersebut.
BooksController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
169
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using SqlServerBookStore.Data;
using SqlServerBookStore.Models;
namespace SqlServerBookStore.Controllers
{
public class Books1Controller : Controller
{
private readonly ApplicationDbContext _context;
// GET: Books1
public async Task<IActionResult> Index()
{
var applicationDbContext = _context.Books.Include(b => b.Categor
y);
return View(await applicationDbContext.ToListAsync());
}
// GET: Books1/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
return View(book);
}
// GET: Books1/Create
public IActionResult Create()
{
ViewData["CategoryID"] = new SelectList(_context.Categories, "Ca
tegoryID", "Name");
return View();
}
// POST: Books1/Create
// To protect from overposting attacks, please enable the specific p
roperties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("BookID,CategoryID,Tit
le,Photo,PublishDate,Price,Quantity")] Book book)
{
if (ModelState.IsValid)
170
{
_context.Add(book);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
ViewData["CategoryID"] = new SelectList(_context.Categories, "Ca
tegoryID", "Name", book.CategoryID);
return View(book);
}
// GET: Books1/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
// POST: Books1/Edit/5
// To protect from overposting attacks, please enable the specific p
roperties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("BookID,Category
ID,Title,Photo,PublishDate,Price,Quantity")] Book book)
{
if (id != book.BookID)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(book);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!BookExists(book.BookID))
{
return NotFound();
}
else
{
throw;
}
}
171
return RedirectToAction(nameof(Index));
}
ViewData["CategoryID"] = new SelectList(_context.Categories, "Ca
tegoryID", "Name", book.CategoryID);
return View(book);
}
// GET: Books1/Delete/5
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}
return View(book);
}
// POST: Books1/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
var book = await _context.Books.SingleOrDefaultAsync(m => m.Book
ID == id);
_context.Books.Remove(book);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
Class controller Books ini tidak hanya akan menggunakan class entity model, tetapi juga akan
menggunakan class view model. Class entity model digunakan untuk melakukan operasi
dasar database yaitu create, retrieve, update dan delete (CRUD). Sedangkan untuk
menampilkan data ke komponen view akan digunakan clas view model. Hal ini perlu
dilakukan untuk menyesuaikan dengan antarmuka halaman view yang diinginkan.
Untuk membuat hal seperti itu, maka perlu ada modifikasi kode class controller yang telah
dibuat secara otomatis oleh Visual Studio. Berikut adalah kode lengkap BooksController
yang telah dimodifikasi.
BooksController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
172
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Hosting;
using System.IO;
using SqlServerBookStore.Data;
using SqlServerBookStore.Models;
namespace SqlServerBookStore.Controllers
{
public class BooksController : Controller
{
private readonly ApplicationDbContext _context;
private IHostingEnvironment _environment;
// GET: Books
public IActionResult Index()
{
var bookList = _context.Books
.Include(c => c.Category)
.Include(ba => ba.BooksAuthors)
.ThenInclude(a => a.Author)
.ToList();
item.ISBN = book.BookID;
item.Title = book.Title;
item.Photo = book.Photo;
item.PublishDate = book.PublishDate;
item.Price = book.Price;
item.Quantity = book.Quantity;
item.CategoryName = book.Category.Name;
items.Add(item);
}
return View(items);
}
// GET: Books/Details/5
public IActionResult Details(int? id)
{
173
var book = _context.Books
.Include(c => c.Category)
.Include(ba => ba.BooksAuthors)
.ThenInclude(a => a.Author).SingleOrDefault(b => b.BookID.Eq
uals(id));
return View(item);
}
// GET: Books/Create
public IActionResult Create()
{
//ViewData["CategoryID"] = new SelectList(_context.Categories, "
CategoryID", "Name");
ViewBag.Categories = new SelectList(_context.Categories.ToList()
, "CategoryID", "Name");
ViewBag.Authors = new MultiSelectList(_context.Authors.ToList(),
"AuthorID", "Name");
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(BookFormViewModel item)
{
if (ModelState.IsValid)
{
Book book = new Book();
book.BookID = item.ISBN;
book.CategoryID = item.CategoryID;
book.Title = item.Title;
book.PublishDate = item.PublishDate;
book.Price = item.Price;
book.Quantity = item.Quantity;
_context.Add(book);
174
}
_context.SaveChanges();
if (item.Photo != null)
{
var file = item.Photo;
var uploads = Path.Combine(_environment.WebRootPath, "up
load");
if (file.Length > 0)
{
using (var fileStream = new FileStream(Path.Combine(
uploads, item.ISBN + ".jpg"), FileMode.Create))
{
file.CopyToAsync(fileStream);
}
}
}
return RedirectToAction("Index");
}
return View();
}
[HttpGet]
public IActionResult Edit(int? id)
{
ViewBag.Categories = new SelectList(_context.Categories.ToList()
, "CategoryID", "Name");
ViewBag.Authors = new MultiSelectList(_context.Authors.ToList(),
"AuthorID", "Name");
return View(item);
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit([Bind("ISBN, CategoryID, Title, Photo, Pub
lishDate, Price, Quantity, AuthorIDs")] BookFormViewModel item)
{
175
if (ModelState.IsValid)
{
_context.BooksAuthors.RemoveRange(_context.BooksAuthors.Wher
e(p => p.BookID.Equals(item.ISBN)));
_context.SaveChanges();
_context.SaveChanges();
if (item.Photo != null)
{
var file = item.Photo;
var uploads = Path.Combine(_environment.WebRootPath, "up
load");
if (file.Length > 0)
{
using (var fileStream = new FileStream(Path.Combine(
uploads, item.ISBN + ".jpg"), FileMode.Create))
{
file.CopyToAsync(fileStream);
}
}
}
return RedirectToAction("Index");
}
return View();
}
// GET: Books/Delete/5
public IActionResult Delete(int? id)
{
var book = _context.Books
.Include(c => c.Category)
.Include(ba => ba.BooksAuthors)
.ThenInclude(a => a.Author).SingleOrDefault(b => b.BookID.Eq
uals(id));
176
item.CategoryName = book.Category.Name;
return View(item);
}
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public IActionResult DeleteConfirmed(int id)
{
if (ModelState.IsValid)
{
_context.BooksAuthors.RemoveRange(_context.BooksAuthors.Wher
e(p => p.BookID.Equals(id)));
_context.SaveChanges();
return RedirectToAction("Index");
}
return View();
}
177
Gambar 125. BooksController - Daftar buku.
Selanjutnya seluruh kode method tersebut akan diganti dengan kode sebagai berikut ini.
Langkah pertama yang dilakukan adalah mengambil data buku dari tabel books dengan cara
berikut ini.
var bookList = _context.Books
.Include(c => c.Category)
.Include(ba => ba.BooksAuthors)
.ThenInclude(a => a.Author)
.ToList();
Cara di atas adalah cara lain untuk mendapatkan seluruh data book. Pada kode di atas dapat
dilihat penggunaan kata kunci Include yang berfungsi untuk memuat data yang terkait
dengan data book yang dipilih. Dari contoh di atas artinya akan dimuat data BooksAuthors
yang sesuai dengan data Book. Kemudian dengan kata kunci ThenInclude akan memuat data
Author yang sesuai dengan data BooksAuthor yang telah dimuat sebelumnya.
Hasilnya disimpan pada object bookList. Selanjutnya setiap object Book akan disimpan pada
object BookViewModel. Kumpulan object BookViewModel akan ditampung di dalam
collection bertipe List dengan cara seperti berikut.
IList<BookViewModel> items = new List<BookViewModel>();
foreach (Book book in bookList)
{
BookViewModel item = new BookViewModel();
item.ISBN = book.BookID;
item.Title = book.Title;
item.Photo = book.Photo;
item.PublishDate = book.PublishDate;
item.Price = book.Price;
item.Quantity = book.Quantity;
item.CategoryName = book.Category.Name;
. . .
items.Add(item);
}
Dari contoh di atas object object items dipersiapkan untuk menyimpan object
BookViewModel. Kemudian dengan melakukan pengulangan dilakukan pengambilan dari
object bookList. Selanjutnya dibuat object item yang merupakan instansiasi dari class view
model BookViewModel. Pada kode di atas dapat dilihat object item diisi dengan nilai-nilai
seperti ISBN, Title, Photo, PublishDate, Price dan Quantity.
item.CategoryName = book.Category.Name;
178
Sedangkan untuk mendapatkan nama kategori buku dapat langsung dilakukan dengan cara
di atas. Hal ini bisa dilakukan karena pada model Book dan Category telah memiliki relasi.
Sebuah buku dapat ditulis oleh lebih dari pengarang. Nama-nama pengarang tersebut akan
disimpan dalam object authorNameList yang bertipe string yang akan dipisahkan oleh tanda
koma (,). Selanjutnya adalah mengambil relasi antara pengarang buku dengan buku dengan
cara berikut ini.
Objek items akan menyimpan data dari tabel author dalam bentuk IList. Selanjutnya object
items akan dikirim ke komponen view Index.cshtml dengan cara berikut.
return View(items);
return View(book);
}
Modifikasi kode ini diperlukan karena ingin menampilkan detail data buku seperti berikut
ini.
179
Gambar 126. BooksController - Detail.
Berikut adalah kode method action Details setelah dimodifikasi.
public IActionResult Details(int? id)
{
var book = _context.Books
.Include(c => c.Category)
.Include(ba => ba.BooksAuthors)
.ThenInclude(a => a.Author).SingleOrDefault(b => b.BookID.Equals(id)
);
return View(item);
}
Isi kode di atas memiliki kemiripan dengan method action Index. Perbedaan paling mendasar
adalah cara mengambil data buku berdasarkan id, seperti yang dapat dilihat pada cetak tebal.
var book = _context.Books
.Include(c => c.Category)
.Include(ba => ba.BooksAuthors)
.ThenInclude(a => a.Author).SingleOrDefault(b => b.BookID.Equals(id));
180
Method Action [HttpGet]Create
Berikut ini adalah kode method action Create.
// GET: Books/Create
public IActionResult Create()
{
ViewData["CategoryID"] = new SelectList(_context.Categories,
"CategoryID", "Name");
return View();
}
Method action ini bertujuan untuk menampilkan form untuk menambah data buku. File
komponen view yang digunakan sebagai form ini adalah Create.cshtml. Berikut adalah
tampilan form untuk menambah data buku.
return View();
}
Pada input Category dan List of Author Names dapat dilihat ditampilkan data dari tabel
Categories dan Authors. Sehingga pada method action ini dapat dilihat kode pengambilan
data dari kedua tabel tersebut dengan menggunakan kode di atas.
Object ViewBag.Categories menyimpan data tabel categories. Dan object ViewBag.Authors
menyimpan data dari tabel authors. Selanjutnya dapat dilihat bagaimana kedua object ini
ditampilkan halaman komponen view Create.cshtml.
181
Method Action [HttpPost]Create
Berikut adalah isi method action Create sebelum dimodifikasi.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("BookID,CategoryID,Title,Photo
,PublishDate,Price,Quantity")] Book book)
{
if (ModelState.IsValid)
{
_context.Add(book);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
ViewData["CategoryID"] = new SelectList(_context.Categories, "CategoryID
", "Name", book.CategoryID);
return View(book);
}
Kode di atas perlu dimodifikasi untuk membuat form tambah data buku seperti pada gambar
berikut ini.
182
bookAuthor.BookID = item.ISBN;
bookAuthor.AuthorID = authorId;
_context.Add(bookAuthor);
}
_context.SaveChanges();
if (item.Photo != null)
{
var file = item.Photo;
var uploads = Path.Combine(_environment.WebRootPath, "upload");
if (file.Length > 0)
{
using (var fileStream = new FileStream(Path.Combine(uploads,
item.ISBN + ".jpg"), FileMode.Create))
{
file.CopyToAsync(fileStream);
}
}
}
return RedirectToAction("Index");
}
return View();
}
Method action ini bertujuan untuk menyimpan nilai-nilai dari object BookFormViewModel
yang property-propertynya telah diisi melalui form pada file Create.cshtml. Agar method ini
dapat menerima kiriman object file Create.cshtml maka dapat dilihat parameter input item
seperti pada kode berikut ini.
public IActionResult Create(BookFormViewModel item)
{
. . .
}
Selanjutnya untuk memvalisidasi item sebelum disimpan dapat dilakukan dengan cara
berikut.
if(ModelState.IsValid){
. . .
}
Karena object BookFormViewModel bukan object dari class entity model, maka model ini
tidak dapat langsung digunakan untuk menyimpan data ke database.
Langkah pertama adalah menyimpan beberapa nilai-nilai dari object BookFormViewModel
ke dalam object Book dengan cara berikut ini.
Book book = new Book();
book.BookID = item.ISBN;
book.CategoryID = item.CategoryID;
book.Title = item.Title;
book.PublishDate = item.PublishDate;
book.Price = item.Price;
book.Quantity = item.Quantity;
_context.Add(book);
Dari kode di atas dapat dilihat sebagian nilai dari object BookFormViewModel telah
dimasukkan ke dalam object entity model Book sehingga bisa disimpan ke dalam database.
Selanjutnya menyimpan nilai property AuthorIDs dari object BookFormViewModel yang
berisi daftar pengarang buku yang dipilih pada form dengan cara berikut ini.
183
foreach (int authorId in item.AuthorIDs)
{
BookAuthor bookAuthor = new BookAuthor();
bookAuthor.BookID = item.ISBN;
bookAuthor.AuthorID = authorId;
_context.Add(bookAuthor);
}
Dari kode di atas dapat dilihat nilai id buku dan id pengarang disimpan di dalam object entity
model BookAuthor. Setelah seluruh nilai-nilai dari object BookFormViewModel dipindahkan
ke object-object entity model Book dan BookAuthor maka selanjutnya dapat dilakukan
penyimpanan data dengan cara berikut.
_context.SaveChanges();
Langkah selanjutnya adalah menangani proses upload file dan menyimpan file tersebut ke
folder upload pada folder wwwroot. Berikut adalah kode yang digunakan untuk menangani
hal tersebut.
if (item.Photo != null)
{
var file = item.Photo;
var uploads = Path.Combine(_environment.WebRootPath, "upload");
if (file.Length > 0)
{
using (var fileStream = new FileStream(Path.Combine(uploads,
item.ISBN + ".jpg"), FileMode.Create))
{
file.CopyToAsync(fileStream);
}
}
}
Setelah data dan file yang diupload sukses disimpan, selanjutnya akan kembali ditampilkan
daftar pengarang buku dengan menggunakan baris berikut ini.
return RedirectToAction("Index");
184
Berikut ini adalah antarmuka form edit data yang akan dibuat.
return View(item);
}
Method action ini bertujuan untuk menampilkan form untuk mengedit data buku yang
dipilih. Untuk mendapatkan data buku yang akan diedit maka pada method ini memiliki
parameter input untuk menerima kiriman id pengarang buku dari komponen view
Index.cshtml.
public IActionResult Edit(int? id)
{
. . .
185
}
Method action ini akan menampilkan komponen view Edit.cshtml. Pada form ini juga
terdapat kode untuk menampung data dari tabel categories dan authors untuk ditampilkan
dengan cara berikut ini.
ViewBag.Categories = new SelectList(_context.Categories.ToList(),
"CategoryID", "Name");
Selanjutnya untuk nilai property AuthorIDs diisi dengan menggunakan kode berikut ini.
var authorList = _context.BooksAuthors.Where(p =>
p.BookID.Equals(book.BookID)).ToList();
item.AuthorIDs = authors.ToArray();
Data buku yang dipilih ditampung oleh object item, kemudian object tersebut dikirim ke
komponen view Edit.cshtml dengan cara seperti berikut.
return View(item);
186
if (ModelState.IsValid)
{
try
{
_context.Update(book);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!BookExists(book.BookID))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
ViewData["CategoryID"] = new SelectList(_context.Categories,
"CategoryID", "Name", book.CategoryID);
return View(book);
}
_context.SaveChanges();
if (item.Photo != null)
{
var file = item.Photo;
var uploads = Path.Combine(_environment.WebRootPath, "upload");
if (file.Length > 0)
187
{
using (var fileStream = new FileStream(Path.Combine(uploads,
item.ISBN + ".jpg"), FileMode.Create))
{
file.CopyToAsync(fileStream);
}
}
}
return RedirectToAction("Index");
}
return View();
}
Method action ini bertujuan untuk menyimpan data buku telah diubah nilai-nilainya melalui
form pada file Edit.cshtml. Agar method ini dapat menerima kiriman object file Edit.cshtml
maka dapat dilihat parameter input item seperti pada kode berikut ini.
public IActionResult Edit([Bind("ISBN, CategoryID, Title, Photo,
PublishDate, Price, Quantity, AuthorIDs")] BookFormViewModel item)
{
. . .
}
Pada parameter input di atas dapat dilihat object item tipe BookFormViewModel. Berbeda
jika dibandingkan dengan parameter input pada method action [HttpPost] Create, method
action ini memiliki tambahan atribut Bind yang berisi nama property-property dari class
entity model. Tujuan penggunaan atribut Bind pada object item adalah untuk mengisi nilai-
nilai property ke object item tersebut.
Selanjutnya adalah memvalidasi object sebelum disimpan dengan kode berikut.
if (ModelState.IsValid)
{
. . .
}
Langkah selanjutnya adalah menghapus record pada tabel books_authors yang memiliki nilai
ISBN yang sama dengan buku yang dipilih untuk diedit ini. berikut adalah kode yang
digunakan.
_context.BooksAuthors.RemoveRange(_context.BooksAuthors.Where(p =>
p.BookID.Equals(item.ISBN)));
_context.SaveChanges();
Langkah selanjutnya adalah memilih object buku yang diedit untuk ditampung pada object
entity model.
Selanjutnya adalah mengubah nilai-nilai property object book dan menyimpan ke database
dengan cara berikut ini.
book.CategoryID = item.CategoryID;
book.Title = item.Title;
book.PublishDate = item.PublishDate;
book.Price = item.Price;
book.Quantity = item.Quantity;
_context.Update(book);
Kemudian menyimpan data pengarang buku yang dipilih dengan cara berikut ini.
188
foreach (int authorId in item.AuthorIDs)
{
BookAuthor bookAuthor = new BookAuthor();
bookAuthor.BookID = item.ISBN;
bookAuthor.AuthorID = authorId;
_context.Add(bookAuthor);
}
_context.SaveChanges();
Kemudian dilakukan pemeriksaan jika ada file cover buku yang diupload. Jika ada file yang
diupload maka akan dilakukan proses penyimpanan file tersebut pada folder
wwwroot/upload.
if (item.Photo != null)
{
var file = item.Photo;
var uploads = Path.Combine(_environment.WebRootPath, "upload");
if (file.Length > 0)
{
using (var fileStream = new FileStream(Path.Combine(uploads,
item.ISBN + ".jpg"), FileMode.Create))
{
file.CopyToAsync(fileStream);
}
}
}
Setelah data sukses disimpan, selanjutnya akan kembali ditampilkan daftar buku dengan
menggunakan baris berikut ini.
return RedirectToAction("Index");
return View(book);
}
Method ini bertujuan untuk menampilkan halaman konfirmasi data yang akan dihapus.
Antarmuka halaman konfirmasi yang akan dibuat adalah sebagai berikut.
189
Gambar 130. BooksController - Delete.
Untuk menyesuaikan dengan antarmuka itu, maka method ini akan dimodifikasi seperti
berikut.
public IActionResult Delete(int? id)
{
var book = _context.Books
.Include(c => c.Category)
.Include(ba => ba.BooksAuthors)
.ThenInclude(a => a.Author).SingleOrDefault(b => b.BookID.Equals(id)
);
return View(item);
}
Isi method action ini sama dengan isi method action Detail.
190
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
var book = await _context.Books.SingleOrDefaultAsync(m => m.BookID ==
id);
_context.Books.Remove(book);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
Dan kode berikut ini adalah isi method action Delete setelah dimodifikasi.
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public IActionResult DeleteConfirmed(int id)
{
if (ModelState.IsValid)
{
_context.BooksAuthors.RemoveRange(_context.BooksAuthors.Where(p => p
.BookID.Equals(id)));
_context.SaveChanges();
return RedirectToAction("Index");
}
return View();
}
Method ini berfungsi untuk menghapus data buku yang dipilih. Agar method ini dapat
menerima id buku untuk dihapus maka diperlukan parameter input seperti berikut.
public IActionResult Delete(int id)
{
. . .
}
Data yang akan dihapus pertama kali adalah data pada BooksAuthors, yang menyimpan
relasi antara data buku dengan pengarang. Berikut adalah kode yang digunakan untuk
menghapus data berdasarkan id dari buku.
_context.BooksAuthors.RemoveRange(_context.BooksAuthors.Where(p => p.BookID.
Equals(id)));
_context.SaveChanges();
Selanjutnya adalah mencari objek buku yang akan dihapus dengan kode berikut ini.
Objek book akan berisi data buku yang akan dihapus. Selanjutnya untuk menghapus buku
dari tabel Books digunakan kode berikut ini.
_context.Books.Remove(book);
191
_context.SaveChanges();
Setelah data sukses dihapus, selanjutnya akan kembali ditampilkan daftar buku dengan
menggunakan baris berikut ini.
return RedirectToAction("Index");
namespace SqlServerBookStore.Controllers
{
public class RoleController : Controller
{
private readonly RoleManager<ApplicationRole> db;
[HttpGet]
public IActionResult Index()
{
192
items = db.Roles.Select(r => new RoleViewModel
{
RoleID = r.Id,
RoleName = r.Name,
Description = r.Description
}).ToList();
return View(items);
}
[HttpGet]
public async Task<IActionResult> Detail(string id)
{
RoleViewModel item = new RoleViewModel();
ApplicationRole role = await db.FindByIdAsync(id);
if (role != null)
{
item.RoleID = role.Id;
item.RoleName = role.Name;
item.Description = role.Description;
}
return View(item);
}
[HttpGet]
public IActionResult Create()
{
return View();
}
[HttpPost]
public async Task<IActionResult> Create(RoleViewModel item)
{
if (ModelState.IsValid)
{
ApplicationRole role = new ApplicationRole();
role.Id = item.RoleID;
role.Name = item.RoleName;
role.Description = item.Description;
return RedirectToAction("Index");
}
return View();
}
[HttpGet]
public async Task<IActionResult> Edit(string id)
{
RoleViewModel item = new RoleViewModel();
ApplicationRole role = await db.FindByIdAsync(id);
if (role != null)
{
item.RoleID = role.Id;
item.RoleName = role.Name;
item.Description = role.Description;
}
return View(item);
}
193
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit([Bind("RoleID,RoleName,Descrip
tion")] RoleViewModel item)
{
if (ModelState.IsValid)
{
ApplicationRole role = await db.FindByIdAsync(item.RoleID);
if (role != null)
{
role.Id = item.RoleID;
role.Name = item.RoleName;
role.Description = item.Description;
var result = await db.UpdateAsync(role);
}
return RedirectToAction("Index");
}
return View();
}
[HttpGet]
public async Task<IActionResult> Delete(string id)
{
RoleViewModel item = new RoleViewModel();
ApplicationRole role = await db.FindByIdAsync(id);
if (role != null)
{
item.RoleID = role.Id;
item.RoleName = role.Name;
item.Description = role.Description;
}
return View(item);
}
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(string id)
{
if (ModelState.IsValid)
{
ApplicationRole role = await db.FindByIdAsync(id);
var result = await db.DeleteAsync(role);
return RedirectToAction("Index");
}
return View();
}
}
}
194
Selanjutnya untuk mengambil data dari database dapat dilakukan dengan menggunakan
kode berikut ini.
var items = new List<RoleViewModel>();
items = db.Roles.Select(r => new RoleViewModel
{
RoleID = r.Id,
RoleName = r.Name,
Description = r.Description
}).ToList();
Cara di atas ini sedikit berbeda dengan cara pengambilan data yang telah dilakukan pada
class controller CategoriesController, AuthorsController atau BooksController. Pada cara di
atas, setelah data role diambil dengan cara seperti pada baris pertama, selanjutnya memilih
property-property yang dimiliki data role untuk disimpan ke property-property object items.
Dan selanjutnya object items dikirim ke komponen view untuk ditampilkan.
return View(items);
Untuk mendapatkan objek role yang dipilih dapat dilihat pada baris yang dicetak tebal.
Selanjutnya untuk menyimpan object tersebut ke dalam database digunakan perintah berikut.
Dengan memanfaatkan parameter input id tersebut maka dapat dilakukan pengambilan data
dengan menggunakan cara berikut ini.
Kemudian data yang ada pada object role akan disimpan kembali ke dalam object item yang
merupakan instansiasi class RoleViewModel.
RoleViewModel item = new RoleViewModel();
if (role != null)
{
item.RoleID = role.Id;
item.RoleName = role.Name;
item.Description = role.Description;
}
Data role yang dipilih ditampung oleh object item, kemudian object tersebut dikirim ke
komponen view Edit.cshtml dengan cara seperti berikut.
return View(item);
Selanjutnya data yang akan diedit mesti dicari terlebih dahulu di dalam database dan
ditampung ke dalam object role berikut ini.
Jika data yang dicari ditemukan atau ketika object role memiliki nilai maka selanjutnya
dilakukan penyimpanan data dengan cara seperti berikut ini.
if (role != null)
{
role.Id = item.RoleID;
role.Name = item.RoleName;
role.Description = item.Description;
var result = await db.UpdateAsync(role);
}
196
Selanjutnya jika proses penyimpanan berhasil maka akan ditampilkan komponen view
Index.html.
197
Berikut ini adalah kode lengkap dari class UserController.cs.
UserController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Identity;
using SqlServerBookStore.Models;
using SqlServerBookStore.Data;
namespace SqlServerBookStore.Controllers
{
public class UserController : Controller
{
private readonly UserManager<ApplicationUser> userManager;
private readonly RoleManager<ApplicationRole> roleManager;
[HttpGet]
public async Task<IActionResult> Index()
{
items.Add(item);
}
return View(items);
}
[HttpGet]
public async Task<IActionResult> Detail(string id)
{
var user = await userManager.FindByNameAsync(id);
198
item.Email = user.Email;
item.FullName = user.FullName;
return View(item);
}
[HttpGet]
public IActionResult Create()
{
ViewBag.Roles = new MultiSelectList(roleManager.Roles.ToList(),
"Id", "Name");
return View();
}
[HttpPost]
public async Task<IActionResult> Create(UserCreateFormViewModel item
)
{
ViewBag.Roles = new MultiSelectList(roleManager.Roles.ToList(),
"Id", "Name");
if (ModelState.IsValid)
{
ApplicationUser user = new ApplicationUser();
user.FullName = item.FullName;
user.UserName = item.UserName;
user.Email = item.Email;
IdentityResult result = await userManager.CreateAsync(user,
item.Password);
if (result.Succeeded)
{
result = await userManager.AddToRolesAsync(user, item.Ro
leID);
if (result.Succeeded)
{
return RedirectToAction("Index");
}
}
}
return View();
}
[HttpGet]
public async Task<IActionResult> Edit(string id)
{
ViewBag.Roles = new MultiSelectList(roleManager.Roles.ToList(),
"Id", "Name");
var user = await userManager.FindByNameAsync(id);
199
UserEditFormViewModel item = new UserEditFormViewModel();
item.UserName = user.UserName;
item.Email = user.Email;
item.FullName = user.FullName;
return View(item);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit([Bind("UserName, RoleID, Email
, Password, PasswordConfirm, FullName")] UserEditFormViewModel item)
{
ViewBag.Roles = new MultiSelectList(roleManager.Roles.ToList(),
"Id", "Name");
if (ModelState.IsValid)
{
ApplicationUser user = await userManager.FindByNameAsync(ite
m.UserName);
user.Email = item.Email;
user.FullName = item.FullName;
var existingRoles = await userManager.GetRolesAsync(user);
IdentityResult result = await userManager.UpdateAsync(user);
if (result.Succeeded)
{
result = await userManager.RemoveFromRolesAsync(user, ex
istingRoles);
if (result.Succeeded)
{
result = await userManager.AddToRolesAsync(user, ite
m.RoleID);
if (result.Succeeded)
{
return RedirectToAction("Index");
}
}
}
}
return View();
}
[HttpGet]
public async Task<IActionResult> Delete(string id)
{
var user = await userManager.FindByNameAsync(id);
200
{
roleNameList = roleNameList + role + ", ";
}
item.RoleName = roleNameList.Substring(0, roleNameList.Length -
2);
return View(item);
}
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(string id)
{
if (ModelState.IsValid)
{
var user = await userManager.FindByNameAsync(id);
var result = await userManager.DeleteAsync(user);
return RedirectToAction("Index");
}
return View();
}
}
}
Pada kode di atas dapat dilihat penambahan dua property pada class UserController yaitu:
1. userManager, adalah object hasil instansiasi class UserManager yang berfungsi
untuk mengakses data user.
2. roleManager, adalah object hasil instansiasi class RoleManager yang berfungsi
untuk mengakses data role.
Class UserManager dan RoleManager adalah bagian dari ASP.NET Core Identity.
Keduanya akan mempermudah untuk mengelola data user dan role. Selain itu pada class
ini juga ditambahkan constructor UserController untuk melakukan inisialisasi nilai pada
property userManager dan roleManager.
Selanjutnya untuk mengambil data user dari database digunakan kode berikut ini.
Selanjutnya adalah melakukan pengulangan untuk memasukan data dari userList ke dalam
object item yang merupakan instansiasi dari class UserViewModel.
foreach (var user in userList)
{
var item = new UserViewModel();
item.UserName = user.UserName;
item.Email = user.Email;
item.FullName = user.FullName;
201
var roleList = await userManager.GetRolesAsync(user);
foreach (var role in roleList)
{
roleNameList = roleNameList + role + ", ";
}
item.RoleName = roleNameList.Substring(0, roleNameList.Length - 2);
items.Add(item);
}
Pada pengulangan di atas juga dapat dilihat bagaimana cara mengambil daftar role dari user
yang kemudian dimasukkan sebagai nilai property RoleName. Setiap user dapat memiliki
sebuah role atau lebih dari satu.
Setelah itu data yang telah ditampung pada object items ditampilkan ke halaman view
Index.cshtml.
return View(items);
Setelah objek user berisi data yang dipilih, selanjutnya digunakan kode berikut untuk mengisi
objek UserViewModel.
UserViewModel item = new UserViewModel();
item.UserName = user.UserName;
item.Email = user.Email;
item.FullName = user.FullName;
return View(item);
202
Method action ini berfungsi untuk menyimpan data user yang telah diisikan pada form input
pada halaman Create.cshtml. Data user dari halaman Create.cshtml dikirimkan via object
item yang merupakan instan dari class UserCreateFormViewModel. Selanjutnya nilai-nilai
pada object item ini akan dimasukkan pada object user yang merupakan instansiasi dari class
model ApplicationUser. Berikut adalah kode yang digunakan.
ApplicationUser user = new ApplicationUser();
user.FullName = item.FullName;
user.UserName = item.UserName;
user.Email = item.Email;
Kemudian pada baris terakhir pada kode di atas adalah cara untuk menyimpan data user ke
dalam database. Method CreateAsync berfungsi untuk membuat user dengan parameter
input nama user dan password.
Jika proses pembuatan user berhasil maka dilanjutkan dengan penambahan role untuk user
tersebut dengan cara berikut ini.
Untuk mengisi form edit dengan data user yang dipilih maka terlebih dahulu perlu dilakukan
pengambilan data user yang dipilih dengan cara berikut ini.
Selanjutnya memindahkan nilai property-property pada object user di atas ke object item yang
merupakan instansiasi dari class view model UserEditFormViewModel.
UserEditFormViewModel item = new UserEditFormViewModel();
item.UserName = user.UserName;
item.Email = user.Email;
item.FullName = user.FullName;
Sedangkan untuk mengambil nilai role dari user tersebut digunakan cara sebagai berikut.
var roles = await userManager.GetRolesAsync(user);
item.RoleID = roles.ToArray();
Dan pada baris kedua dapat dilihat data role disimpan ke dalam property RoleID.
203
public async Task<IActionResult> Edit([Bind("UserName, RoleID, Email,
Password, PasswordConfirm, FullName")] UserEditFormViewModel item)
{
. . .
}
Pada method action di atas dapat dilihat terdapat parameter input item yang object yang
dibentuk dari class UserEditFormViewModel. Dengan method Bind yang terlihat pada kode
di atas maka object item ini telah diisi dengan nilai-nilai yang dimasukkan pada form
Edit.cshtml.
Selanjutnya data user yang akan diedit diambil dari database dengan cara berikut ini.
Kemudian mengisi nilai-nilai baru ke dalam property-property pada object user dan
kemudian menyimpan ke dalam database.
user.Email = item.Email;
user.FullName = item.FullName;
Selanjutnya adalah memperbaharui data role dari user tersebut dengan cara menghapus
terlebih dahulu data role yang lama dari user tersebut. Kemudian memasukkan data role
baru pada user tersebut.
var existingRoles = await userManager.GetRolesAsync(user);
if (result.Succeeded)
{
result = await userManager.RemoveFromRolesAsync(user, existingRoles);
if (result.Succeeded)
{
result = await userManager.AddToRolesAsync(user, item.RoleID);
if (result.Succeeded)
{
return RedirectToAction("Index");
}
}
}
204
}
item.RoleName = roleNameList.Substring(0, roleNameList.Length - 2);
return View(item);
Dan untuk menghapus data user tersebut digunakan kode berikut ini.
return RedirectToAction("Index");
View
Pada bab sebelumnya telah dijelaskan fungsi komponen view untuk menampilkan halaman
web sebagai antarmuka agar user dapat berinteraksi dengan aplikasi. Pada halaman web ini
dapat dimanfaatkan untuk menampilkan data dalam bentuk tabel, menampilkan form input
dan lain-lain.
Akses File
Pada aplikasi web, sudah umum untuk menggunakan style CSS dan kode JavaScript untuk
membantu membuat antarmuka. Biasanya kode style CSS dan JavaScript tersebut dapat
disimpan pada sebuah file. Dan untuk mengakses file tersebut dari halaman web, biasanya
digunakan kode seperti baris berikut ini.
<link href="css/bootstrap-responsive.min.css" rel="stylesheet">
<script src="js/jquery-1.9.1.min.js"></script>
Pada atribut href atau src dapat dilihat bagaimana cara menentukan lokasi file yang akan
diakses. Pada ASP.NET Core, file-file JavaScript, CSS atau gambar dikelompokkan sebagai
file static. File-file ini disimpan dalam folder wwwroot. Jika file script JavaScript disimpan
di dalam folder wwwroot/js dan file CSS disimpan di dalam folder wwwroot/css, maka cara
mengakses file-file tersebut dipermudah dengan cara sebagai berikut ini.
<link href="~/css/bootstrap-responsive.min.css" rel="stylesheet">
<script src="~/js/jquery-1.9.1.min.js"></script>
205
Razor
Komponen view adalah halaman web yang berisi kode HTML, CSS dan juga Javascript. Pada
framework ASP.NET Core MVC dapat digunakan Razor. Razor adalah sintaks markup untuk
melekatkan kode server side pada halaman web di komponen view. Sintaks Razor terdiri atas
Razor markup, C# dan HTML. File yang menggunakan sintaks Razor harus disimpan ke
dalam file .cshtml.
Persiapan
Setelah mengunduh source code template dari link https://github.com/puikinsh/gentelella,
maka langkah selanjutnya adalah extract file gentelella-master.zip. Berikut adalah file dan
folder yang template ini.
206
- css.
- images.
- js.
Layout
Langkah selanjutnya adalah membuat layout. Layout aplikasi Book Store memiliki bagian
atau area sebagai berikut.
207
Dengan menggunakan template gentelella maka dapat dibuat master layout seperti gambar
berikut ini.
Kode @RenderBody() adalah expression Razor yang berfungsi untuk memanggil content ada
komponen view yang dipanggil pada method action di class controller.
Berikut adalah isi lengkap file _Layout.cshtml yang telah dimodifikasi.
_Layout.cshtml
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<!-- Meta, title, CSS, favicons, etc. -->
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
208
<title>ASP.NET Core MVC: Book Store</title>
<body class="nav-md">
<div class="container body">
<div class="main_container">
<div class="col-md-3 left_col">
<div class="left_col scroll-view">
<div class="navbar nav_title" style="border: 0;">
<a href="index.html" class="site_title"><i class="fa
fa-book"></i> <span>Book Store</span></a>
</div>
<div class="clearfix"></div>
<br />
209
<a><i class="fa fa-
home"></i> Home <span class="fa fa-chevron-down"></span></a>
<ul class="nav child_menu">
<li><a asp-controller="Home" asp-
action="Index">Dashboard</a></li>
</ul>
</li>
<li>
<a><i class="fa fa-
table"></i> Data <span class="fa fa-chevron-down"></span></a>
<ul class="nav child_menu">
<li><a asp-
controller="Category" asp-action="Index">Book Categories</a></li>
<li><a asp-controller="Author" asp-
action="Index">Authors</a></li>
<li><a asp-controller="Book" asp-
action="Index">Books</a></li>
</ul>
</li>
<li>
<a><i class="fa fa-
table"></i> Security <span class="fa fa-chevron-down"></span></a>
<ul class="nav child_menu">
<li><a asp-controller="Role" asp-
action="Index">Roles</a></li>
<li><a asp-controller="User" asp-
action="Index">Users</a></li>
</ul>
</li>
<li>
<a><i class="fa fa-bar-chart-
o"></i> Reports <span class="fa fa-chevron-down"></span></a>
<ul class="nav child_menu">
<li><a href="#">Book by Category Cha
rt</a></li>
<li><a href="#">Book Selling</a></li
>
</ul>
</li>
</li>
</ul>
</div>
</div>
<!-- /sidebar menu -->
<!-- /menu footer buttons -->
<div class="sidebar-footer hidden-small">
<a data-toggle="tooltip" data-
placement="top" title="Settings">
<span class="glyphicon glyphicon-cog" aria-
hidden="true"></span>
</a>
<a data-toggle="tooltip" data-
placement="top" title="FullScreen">
<span class="glyphicon glyphicon-
fullscreen" aria-hidden="true"></span>
</a>
<a data-toggle="tooltip" data-
placement="top" title="Lock">
<span class="glyphicon glyphicon-eye-
close" aria-hidden="true"></span>
210
</a>
<a data-toggle="tooltip" data-
placement="top" title="Logout" asp-controller="Home" asp-action="Logout">
<span class="glyphicon glyphicon-off" aria-
hidden="true"></span>
</a>
</div>
<!-- /menu footer buttons -->
</div>
</div>
211
</span>
<span class="message">
Film festivals used to be do
-or-die moments for movie makers. They were where...
</span>
</a>
</li>
<li>
<a>
<span class="image"><img src="~/
images/img.jpg" alt="Profile Image" /></span>
<span>
<span>John Smith</span>
<span class="time">3 mins ag
o</span>
</span>
<span class="message">
Film festivals used to be do
-or-die moments for movie makers. They were where...
</span>
</a>
</li>
<li>
<a>
<span class="image"><img src="~/
images/img.jpg" alt="Profile Image" /></span>
<span>
<span>John Smith</span>
<span class="time">3 mins ag
o</span>
</span>
<span class="message">
Film festivals used to be do
-or-die moments for movie makers. They were where...
</span>
</a>
</li>
<li>
<a>
<span class="image"><img src="~/
images/img.jpg" alt="Profile Image" /></span>
<span>
<span>John Smith</span>
<span class="time">3 mins ag
o</span>
</span>
<span class="message">
Film festivals used to be do
-or-die moments for movie makers. They were where...
</span>
</a>
</li>
<li>
<div class="text-center">
<a>
<strong>See All Alerts</stro
ng>
<i class="fa fa-angle-
right"></i>
</a>
</div>
212
</li>
</ul>
</li>
</ul>
</nav>
</div>
</div>
<!-- /top navigation -->
<!-- -----------------------------------------------------------
-- -->
<!-- page content -->
<div class="right_col" role="main">
@RenderBody()
</div>
<!-- /page content -->
<!-- -----------------------------------------------------------
-- -->
<!-- footer content -->
<footer>
<div class="pull-right">
Gentelella - Bootstrap Admin Template by <a href="https:
//colorlib.com">Colorlib</a>
</div>
<div class="clearfix"></div>
</footer>
<!-- /footer content -->
</div>
</div>
213
<script src="~/vendors/DateJS/build/date.js"></script>
<!-- JQVMap -->
<script src="~/vendors/jqvmap/dist/jquery.vmap.js"></script>
<script src="~/vendors/jqvmap/dist/maps/jquery.vmap.world.js"></script>
<script src="~/vendors/jqvmap/examples/js/jquery.vmap.sampledata.js"></s
cript>
<!-- bootstrap-daterangepicker -->
<script src="~/vendors/moment/min/moment.min.js"></script>
<script src="~/vendors/bootstrap-
daterangepicker/daterangepicker.js"></script>
</body>
</html>
Source code _Layout.cshtml ini juga dapat dilihat pada link GitHub yang telah disebutkan
pada bab Pendahuluan sub bab Bahan Pendukung.
Content
Seperti yang telah disebutkan di atas, content akan berisi file view yang dipanggil oleh
method action. Sebuah file view ini dapat berdiri sendiri tanpa layout atau dapat juga
menggunakan layout.
Jika file view ingin berdiri sendiri tanpa menggunakan layout, maka di awal file tersebut
dapat ditambahkan baris berikut ini.
@{
Layout = null;
}
Jika sebuah file view ingin menggunakan master layout maka di awal file tersebut dapat
menggunakan baris berikut ini.
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
Jika project aplikasi web memiliki banyak file view, misal ada dimiliki 10 controller dan
disetiap controller memiliki 4 method action maka akan dimiliki 40 file view. Jika seluruh file
view menggunakan file _Layout.cshtml sebagai layout maka pada 40 file view tersebut harus
ditambahkan baris di atas.
Untuk otomatisasi agar seluruh file-file view menggunakan file layout yang sama dapat
dilakukan dengan cara berikut ini. Langkah pertama adalah membuat file _ViewStart.cshtml
yang disimpan pada folder Views. File ini adalah file yang akan dibaca oleh seluruh file view.
Kemudian pada file _ViewStart.cshtml diisi dengan kode di bawah ini.
_ViewStart.cshtml
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
214
@using SqlServerBookStore
@using SqlServerBookStore.Models
@using SqlServerBookStore.Models.AccountViewModels
@using SqlServerBookStore.Models.ManageViewModels
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Persiapan
Agar pembaca dapat mencoba langsung penjelasan dan contoh-contoh pada sub bab ini maka
terlebih dulu dapat melakukan persiapan untuk membuat komponen control dan komponen
view sebagai berikut.
Untuk latihan akan dibuat controller baru yaitu Latihan dengan menambahkan file
LatihanController.cs pada folder Controllers.
LatihanController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace SqlServerBookStore.Controllers
{
public class LatihanController : Controller
{
public IActionResult Index()
{
return View();
}
}
}
Langkah selanjutnya adalah membuat komponen view dengan cara terlebih dahulu membuat
folder Latihan pada folder Views. Kemudian menambahkan file Index.cshtml pada folder
Views\Latihan.
Index.cshtml
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
215
<meta name="viewport" content="width=device-width" />
<title>Latihan</title>
</head>
<body>
<h1>Latihan</h1>
</body>
</html>
Untuk mengakses halaman ini dapat dilakukan dengan memanggil controller Latihan dengan
cara berikut ini.
https://localhost:44364/Latihan
Simbol @
Simbol @ adalah penanda awal dari yang digunakan oleh Razor untuk melakukan transisi
dari HTML ke kode C#. Kemudian Razor akan mengevaluasi ekspresi C# dan menulis
outputnya dalam bentuk HTML. Jika simbol @ diikuti oleh keyword Razor maka akan
dilakukan transisi menjadi markup spesifik, selain itu akan dilakukan transisi menjadi kode
C#.
Karena penggunaan simbol @ merupakan penanda awal sintaks Razor, maka penulisan
simbol ini pada halaman file *.cshtml yang tidak mengikuti kaidah penulisan sintaks Razor
akan membuat terjadinya kesalahan pemrograman. Sebagai contoh, jika ingin menulis nama
user Twitter @mrezafaisal pada halaman ini, maka dipastikan Razor akan menganggap
“mrezafaisal” di belakang simbol @ sebagai keyword Razor atau ekspresi C#. Tetapi karena
“merezafaisal” tidak ditemukan didalam keyword Razor atau C# maka akan dapat dilihat
pesan kesalahan seperti gambar di bawah ini.
216
@@mrezafaisal
<a href="mailto:[email protected]">[email protected]</a>
Reserved Keyword
Reserverd keyword terbagi atas dua yaitu:
- Razor keyword.
- C# Razor keyword
Berikut adalah Razor keyword yang dapat digunakan pada ASP.NET Core, yaitu:
- functions.
- inherits.
- model.
- section.
Contoh penulisan keyword ini adalah sebagai berikut.
@functions{
string HelloWorld()
{
return "Hello World";
}
}
217
- foreach.
- if.
- lock.
- switch.
- try.
- using.
- while.
Ekspresi
Ekspresi atau expression adalah baris yang berfungsi untuk menampilkan nilai dari suatu
variable atau output dari suatu fungsi. Ekspresi dapat dibedakan menjadi beberapa tipe,
yaitu:
- Ekspresi implisit (implicit expression).
Ekspresi ini diawali dengan simbol @ dan diikuti oleh kode C#. Dengan cara dapat
digunakan untuk mengeksekusi method generic yang dimiliki suatu class. Berikut
adalah contoh ekspresi implisit.
<h2>Ekspresi implisit</h2>
<p>@DateTime.Now</p>
<p>@DateTime.IsLeapYear(2016)</p>
<p>@DateTime.IsLeapYear(2017)</p>
<p>@HelloWorld()</p>
- Ekspresi Encoding.
Ekspresi encoding adalah ekspresi C# untuk melakukan encoding kode HTML agar
bisa ditampilkan pada halaman web. berikut adalah contoh implementasi ekspresi
encoding ini.
@("<span>Hello World</span>")
Hasil ketiga contoh ekspresi di atas dapat dilihat pada gambar di bawah ini.
218
Gambar 137. Razor - Ekspresi implisit & eksplisit.
Blok Kode
Blok kode Razor diawali dengan simbol @ kemudian diikuti dengan tanda {}. Berbeda dengan
ekspresi, kode yang berada di dalam blok kode ini tidak dirender. Berikut adalah contoh
implementasi blok kode.
@{
var output = "Hello World";
}
Jika kode di atas ditulis pada Index.cshtml, maka dapat dilihat tidak ada output yang dapat
dilihat pada web browser. Jika ingin menampilkan nilai variable output agar dapat dilihat
pada web browser maka perlu digunakan ekspresi sebagai berikut.
219
- Implicit transitions.
Di dalam blok kode selain dapat berisi kode C# juga dapat berisi kode HTML. Kode
HTML yang berada di dalam blok kode akan dirender kembali menjadi kode HTML.
Berikut adalah contoh implementasi cara ini.
@{
var nama = "M Reza Faisal";
<p>Hello @nama</p>
}
Jika bagian di dalam blok tidak menggunakan tag HTML seperti contoh berikuti ini,
maka “Bilangan” dianggap sebagai kode C# sehingga akan terjadi kesalahan, karena
kata “Bilangan” bukan keyword C#.
Hasil dari ketiga cara di atas dapat dilihat pada gambar di bawah ini.
220
Percabangan
Untuk melakukan pemeriksaan kondisi atau percabangan digunakan keyword berikut ini:
- @if, else if, else.
- @switch.
Berikut adalah contoh penulisan @if, else if, else.
@{var value = 5;}
@if (value % 2 == 0)
{
<p>Bilangan genap</p>
}
else if (value >= 11)
{
<p>Bilangan lebih besar dari 11.</p>
}
else
{
<p>Bilangan lebih kecil dari 11 dan ganjil.</p>
}
Sedangkan untuk keyword @switch dapat dilihat contoh penggunaannya di bawah ini.
@switch (value)
{
case 1:
<p>Nilai adalah 1!</p>
break;
case 10:
<p>Nilai adalah 10!</p>
break;
default:
<p>Nilai bukan 1 atau 10.</p>
break;
}
Pengulangan
Untuk pengulangan dapat digunakan keyword @for, @foreach, @while dan @do while.
Berikut adalah contoh penggunakan keyword untuk pengulangan. Pada contoh di bawah ini
dapat dilihat terdapat array names yang berisi 3 item.
<h2>Pengulangan</h2>
@{
string[] names = new string[3];
names[0] = "wati";
names[1] = "budi";
names[2] = "iwan";
}
<h3>@@for</h3>
@for (int i = 0; i < names.Length; i++)
{
<text>@names[i] </text>
}
<h3>@@foreach</h3>
@foreach (var name in names)
{
<text>@name </text>
}
<h3>@@while</h3>
221
@{ var j = 0; }
@while (j < names.Length)
{
<text>@names[j] </text>
j++;
}
<h3>@@do while</h3>
@{ var k = 0; }
@do
{
<text>@names[k] </text>
k++;
} while (k < names.Length);
Directive
Pada Razor terdapat beberapa directive penting yang dapat digunakan dengan fungsinya
masing-masing.
Pada C#, keyword using digunakan untuk memastikan object siap digunakan. Pada Razor,
hal seperti itu juga dapat dilakukan dengan menggunakan directive @using. Cara
penggunaan directive @using akan dapat dilihat dalam penggunaan HTML Helper. Sebagai
contoh digunakan untuk merender tag form seperti contoh di bawah ini.
@using (Html.BeginForm())
{
<div>
email:
<input type="email" id="Email" name="Email" value="" />
<button type="submit"> Register </button>
</div>
}
Directive penting lainnya adalah @model yang terlihat pada halaman-halaman view pada
project MyGuestBook atau EFCoreGuestBook. Directive ini berfungsi untuk menentukan
222
model yang digunakan pada suatu halaman view. Directive ini hanya dapat digunakan sekali
pada halaman view. Contoh penggunaan directive ini dapat dilihat pada aplikasi
MyGuestBook dan EFCoreGuestBook. Sebagai contoh pada project EFCoreGuestBook dapat
dilihat pada file Create.cshtml pada folder Views/Home.
. . .
@model EFCoreGuestBook.Models.GuestBook
. . .
Contoh di atas digunakan untuk mengakses sebuah object dari model tersebut saja. Cara di
atas biasanya digunakan pada halaman view untuk menampilkan form input dari model
tersebut. Atau menampilkan detail informasi dari model tersebut.
Contoh yang lain juga dapat dilihat pada halaman Index.cshtml, dimana directive @model
ditulis sebagai berikut.
@model IList<EFCoreGuestBook.Models.GuestBook>
Dari contoh di atas dapat dilihat directive @model juga dapat mengelola object collection
suatu class model. Cara ini biasanya digunakan untuk menampilkan data pada tabel seperti
pada gambar berikut.
Exception Handling
Untuk penanganan kesalahan atau exception handling, seperti pada C#, maka dapat
digunakan cara yang sama yaitu menggunakan statement @try, catch, finally. Berikut adalah
contoh exception handling pada Razor.
@try
{
throw new InvalidOperationException("Terjadi kesalahan.");
}
catch (Exception ex)
{
<p>Pesan kesalahan: @ex.Message</p>
}
finally
{
<p>Silakan lakukan aksi sekali lagi.</p>
}
223
Komentar
Untuk membuat komentar atau agar suatu baris tidak dieksekusi atau dinon-aktifkan dapat
dilakukan dengan menggunakan cara penulisan sintaks Razor seperti berikut ini.
@{
/*
komentar 1
komentar 2
komentar 3
*/
// komentar
}
Cara di atas dilakukan jika baris berada di dalam blok kode Razor. Jika ingin melakukan
menon-aktifkan blok kode Razor dapat digunakan cara sebagai berikut.
@*
@{
/*
komentar 1
komentar 2
komentar 3
*/
// komentar
}
*@
HTML Helper
HTML Helper adalah method yang output menghasilkan tag-tag HTML seperti tag untuk
membuat link, label, form dan komponen-komponennya seperti input, textarea, select dan
lain-lain. Berberapa HTML Helper telah digunakan pada aplikasi web SqlServerDbFirst dan
SqlServerCodeFirst.
Berikut adalah daftar lengkap dari HTML Helper:
- Html.Beginform.
- Html.EndForm.
- Html.Label.
- Html.TextBox.
- Html.TextArea.
- Html.Password.
- Html.DropDownList.
- Html.CheckBox.
- Html.RedioButton.
- Html.ListBox.
- Html.Hidden.
Jika pada halaman view terdapat form atau table yang digunakan untuk menampilkan data
atau mengirimkan data berdasarkan suatu model, maka dapat digunakan HTML Helper di
bawah ini:
- Html.LabelFor.
- Html.TextBoxFor.
224
- Html.TextAreaFor.
- Html.DropDownListFor.
- Html.CheckBoxFor.
- Html.RadioButtonFor.
- Html.ListBoxFor.
- Html.HiddenFor.
Link
Untuk membuat hyperlink dapat digunakan HTML Helper dengan sintaks berikut ini.
Keterangan:
- text, teks yang akan dilihat pada hyperlink.
- action, nama method action yang digunakan.
- controller, nama controller yang digunakan.
- value, nilai yang digunakan sebagai parameter pada method action.
- htmlAttribute, nilai yang dapat dimasukkan sebagai atribut pada hyperlink.
Berikut adalah contoh penggunaannya.
@Html.ActionLink("Dashboard", "Index", "Home", new { id = "123"}, new { @cla
ss = "style1"})
Helper lain yang dapat digunakan untuk membuat hyperlink adalah method dengan sintaks
berikut ini.
/Home/Index/123
Dari output di atas dapat dilihat jika method @Url.Action hanya akan bernilai string dengan
format di atas. Sehingga method ini tidak dapat berdiri sendiri tetapi harus digunakan pada
tag HTML seperti contoh berikut ini.
<a href='@Url.Action("Index", "Home", new {id = "123"})'>Dashboard</a>
225
Label & Display
Method HTML Helper berikut ini digunakan untuk menampilkan label dengan sintaks
sebagai berikut.
Selain itu juga dapat digunakan method dengan sintaks berikut ini.
@Html.LabelFor(expression)
Method ini biasanya digunakan untuk menampilkan atribut [Display(Name = value)] yang
dimiliki oleh property dari class model. Sebagai contoh untuk class model Category maka
digunakan kode di bawah.
@model SqlServerBookStore.Models.Category
Untuk atribut for berisi dengan nama property yang menjadi nilai expression method ini,
sebagai contoh pada baris terakhir digunakan “m => m.Name” sebagai nilai expression, dan
dapat dilihat nilai atribut for adalah Name. Untuk atribut Name, method ini akan
menampilkan “Book Category Name” yang merupakan nilai dari atribut [Display(Name =
“Book Category Name”)] dari property ini. Jika property class model tidak memiliki atribut
ini, maka yang ditampilkan adalah nama property itu sendiri.
Sedangkan untuk kasus menampilkan data pada tabel digunakan method dengan sintaks
seperti berikut ini.
@Html.DisplayFor(expression)
Contoh kasus ini dapat dilihat pada file Index.cshtml pada folder yang sama dengan file
Create.cshtml di atas.
@model IEnumerable<SqlServerDbFirst.Models.GuestBook>
. . .
@foreach (var item in Model) {
. . .
@Html.DisplayFor(modelItem => item.Name)
. . .
}
Method tersebut tidak akan merender tag HTML tetapi hanya nilai dari property yang
dipanggil yaitu nilai property Name dari class model GuestBook.
226
Form
Untuk membuat form, langkah pertama yang dilakukan adalah dengan cara menggunakan
method dengan sintaks berikut ini.
@using (Html.BeginForm("action", "controller"))
{
// komponen input
}
Keterangan:
- action, nama method action.
- controller, nama class controller.
Berikut adalah contoh penggunakan method di atas.
@using (Html.BeginForm("Index", "Home"))
{
}
</form>
Pada contoh di atas dapat dilihat cara menentukan nilai atribut action pada suatu form.
Method di atas juga dapat ditulis singkat seperti berikut.
@using (Html.BeginForm())
{
}
Jika kode di atas berada pada file yang dipanggil oleh method action Create dari controller
Home seperti yang telah dicontohkan pada aplikasi EFCoreGuestBook di sub bab
sebelumnya. Jika tidak ditentukan nilai parameter action dan controller seperti contoh
sebelumnya, maka nilai parameter ini akan disesuaikan dengan method action dan controller
yang menggunakan file view tersebut. Artinya method di atas akan dirender menjadi tag
HTML berikut.
<form action="/Home/Create" method="post">
</form>
Setelah tag form dibuat dengan method di atas, maka komponen-komponen input dapat
diletakkan didalamnya.
Method-method HTML Helper yang dapat digunakan di dalam @Html.BeginForm() dapat
dibagi menjadi dua tipe, yaitu:
1. Standard, tipe HTML Helper ini digunakan tanpa ada hubungan dengan class model.
Berikut adalah daftar HTML Helper tipe ini, yaitu:
- @Html.TextBox
- @Html.TextArea
- @Html.Password
- @Html.Hidden
- @Html.CheckBox
- @Html.RadioButton
- @Html.DropDownList
- @Html.ListBox
- @Html.TextArea
2. Strongly Typed, tipe ini digunakan bersama dengan class model. Berikut
- @Html.TextBoxFor
227
- @Html.PasswordFor
- @Html.HiddenFor
- @Html.CheckBoxFor
- @Html.RadioButtonFor
- @Html.DropDownListFor
- @Html.ListBoxFor
- @ Html.TextAreaFor
Input Teks
Dari HTML Helper di atas beberapa diantaranya dapat digunakan sebagai input text pada
form. Input text tipe standar dapat digunakan dengan sintaks berikut ini.
Sedangkan untuk tipe strongly typed input teks dapat digunakan dengan sintaks sebagai
berikut ini.
@Html.TextBoxFor(expression, htmlAttribute)
Berikut adalah contoh penggunaan method di atas dengan menggunakan class model
Category.
@model SqlServerBookStore.Models.Category
@using (Html.BeginForm())
{
@Html.LabelFor(m => m.Name)
@Html.TextBoxFor(m => m.Name, new {@class = "style1"})
<br/>
<button type="submit" class="btn btn-success">Submit</button>
}
Untuk baris yang menggunakan method @Html.TextBoxFor akan dirender menjadi tag
HTML berikut ini.
<input class="input-validation-error style1"
data-val="true"
data-val-length="Book Category Name tidak boleh lebih 256 karakter."
data-val-length-max="256"
data-val-required="Book Category Name harus diisi."
id="Name"
name="Name"
type="text"
value="" />
228
Hasil render di atas selain berisi informasi sesuai dengan nilai parameter yang dimasukkan
pada method @Html.TextBoxFor juga berasal dari informasi dari atribut-atribut dari property
Name pada class model Category.
Method lain yang dapat digunakan adalah @Html.TextArea dengan sintaks sebagai berikut
ini.
Sedangkan sintaks text area tipe strongly typed adalah sebagai berikut.
@Html.TextAreaFor(expression, value, htmlAttribute)
@using (Html.BeginForm())
{
@Html.LabelFor(m => m.Name)<br/>
@Html.TextAreaFor(m => m.Name, new {@class = "style1"})
<br/>
<button type="submit" class="btn btn-success">Submit</button>
}
@using (Html.BeginForm())
{
@Html.LabelFor(m => m.CategoryID)
@Html.DropDownListFor(m => m.CategoryID,
new SelectList(new List<Object> {
new { value = "1", text ="Computer" },
new { value = "2", text ="History" }
}, "value", "text", ""), "Choose Book Category")
Method lain yang dapat digunakan @Html.RadioButton dengan contoh sebagai berikut.
@Html.RadioButton("RadioButtonCategory", "1") <span>Computer</span>
229
@Html.RadioButton("RadioButtonCategory", "2") <span>History</span>
@using (Html.BeginForm())
{
@Html.LabelFor(m => m.CategoryID)
@Html.RadioButtonFor(m => m.CategoryID, "1") <span>Computer</span>
@Html.RadioButtonFor(m => m.CategoryID, "2") <span>History</span>
<br/>
<button type="submit" class="btn btn-success">Submit</button>
}
Hasil dari method @Html.RadioButtonFor akan menghasilkan tag HTML seperti berikut ini.
<input data-val="true"
data-val-regex="Category ID harus angka" data-val-regex-pattern="^[0-
9]*$" data-val-required="Category ID harus diisi."
id="CategoryID" name="CategoryID" type="radio" value="1" />
<span>Computer</span>
230
Tombol
Untuk membuat tombol submit data tidak tersedia HTML Helper, sehingga cukup digunakan
tag HTML untuk membuat tombol seperti contoh berikut ini.
<button type="submit">Simpan</button>
<button type="reset">Batal</button>
Validasi
Validasi adalah proses untuk memeriksa kebenaran dari nilai yang dimasukkan pada
komponen input pada form. Implementasi validasi pada form dilakukan dengan
menambahkan @Html.ValidationSummary(true) di dalam blok @Html.BeginForm seperti
contoh di bawah ini.
@model SqlServerBookStore.Models.Category
@using (Html.BeginForm())
{
@Html.ValidationSummary(true)
Jika ingin melakukan validasi input textbox di atas maka cukup dengan menambahkan
method @Html.ValidationMessageFor setelah method @Html.TextBoxFor. Dapat dilihat pada
kedua method tersebut menggunakan expression yang sama yaitu “m => m.Name”.
Berikut ini adalah hasil render menjadi tag HTML dari kode di atas.
<form action="/Latihan/Template" method="post">
<input class="style1"
data-val="true"
data-val-length="Book Category Name tidak boleh lebih 256 karakter."
data-val-length-max="256"
data-val-required="Book Category Name harus diisi."
id="Name" name="Name" type="text" value="" />
<br/><br/>
231
Gambar 142. Tampilan form sebelum proses validasi.
Jika input textbox tidak diisi dan tombol submit diklik maka akan ditampilkan pesan
kesalahan berikut ini.
<br/><br/>
232
</form>
Proses validasi di atas adalah proses validasi server side, artinya perubahan atau penampilan
pesan kesalahan dilakukan oleh pemrograman server side. Proses validasi server side ini
dilakukan oleh method action pada class controller. Penjelasan proses validasi ini akan
dijelaskan pada sub bab Controller.
Catatan
Ada dua hal yang perlu diperhatikan jika menggunakan HTML Helper pada komponen view.
Yang pertama adalah jika telah dibuat design tampilan form dengan antarmuka seperti
berikut ini.
233
Middle Name / Initial
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input id="middle-name" class="form-control col-md-7 col-xs-12"
type="text" name="middle-name">
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">Gender
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<div id="gender" class="btn-group" data-toggle="buttons">
<label class="btn btn-default"
data-toggle-class="btn-primary"
data-toggle-passive-class="btn-default">
<input type="radio" name="gender" value="male">
Male
</label>
<label class="btn btn-primary"
data-toggle-class="btn-primary"
data-toggle-passive-class="btn-default">
<input type="radio" name="gender" value="female">
Female
</label>
</div>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">
Date Of Birth
<span class="required">*</span>
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input id="birthday"
class="date-picker form-control col-md-7 col-xs-12"
required="required" type="text">
</div>
</div>
<div class="ln_solid"></div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-md-offset-3">
<button class="btn btn-primary" type="button">Cancel</button>
<button class="btn btn-primary" type="reset">Reset</button>
<button type="submit" class="btn btn-success">Submit</button>
</div>
</div>
</form>
Jika hasil design di atas akan digunakan sebagai halaman view maka tag <form> dan tag
<input> di atas harus diubah menjadi method HTML Helper yang telah dipelajari
sebelumnya. Dari kasus ini dapat dilihat bahwa hasil design tidak dapat langsung digunakan
sebagai halaman view.
Hal yang kedua adalah ketika halaman view atau master layout yang telah menggunakan
HTML Helper perlu diubah designnya oleh web designer. Maka web design tidak bisa
mengubah atau memperbaiki design jika tidak memiliki pengetahuan tentang sintaks Razor.
Selain itu sintaks Razor dan method HTML Helper akan membuat antarmuka saat dilihat
pada tool web design yang digunakan oleh web designer.
234
Dari kedua hal tersebut maka perlu ada cara alternatif untuk membuat halaman view. Salah
satu caranya adalah dengan menggunakan Tag Helper.
Tag Helper
Seperti disebutkan di atas keberadaan tag helper dapat menjadi cara alternatif untuk
membuat halaman view. Untuk aplikasi SqlServerDbFirst dan SqlServerCodeFirst telah
menggunakan tag helper.
Secara umum fungsi HTML helper dan tag helper adalah sama, yaitu digunakan untuk
membuat link, label, display, form dan lain-lain. Namun dengan cara yang berbeda. Berikut
ini adalah penjelasan cara menggunaan tag helper dan contoh-contohnya terkait dengan
pembangunan aplikasi EFCoreBookStore.
Persiapan
Untuk menggunakan tag helper pada halaman view, maka harus ditambahkan baris berikut
ini pada file _ViewImports.cshtml.
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Link
Berikut ini adalah tag HTML yang digunakan untuk membuat link.
<a href="~/Category/Create" class="style1">
Add Data
</a>
Dengan menggunakan tag helper maka kedua tag HTML di atas dapat ditulis dengan sintaks
berikut ini.
Dari sintaks di atas dapat dilihat bahwa tag helper tetap menggunakan tag HTML sebagai
dasar. Yang membedakan dengan tag HTML biasa adalah pada atribut-atribut yang hanya
dimiliki oleh tag helper yaitu:
- asp-controller, atribut yang bernilai nama controller.
- asp-action, atribut yang bernilai nama action.
Sehingga kedua tag HTML di atas dapat dengan mudah diubah menjadi tag helper dengan
cara di bawah ini.
<a asp-controller="Category" asp-action="Create" class="style1">Test</a>
235
Dengan menggunakan tag helper, elemen HTML dapat memiliki gabungan atribut-atribut
HTML dan atribut-atribut tag helper.
Label
Sintaks Tag Helper untuk label adalah sebagai berikut.
<label asp-for="property_name"></label>
Keterangan:
- property_name, nama property dari class model yang akan ditampilkan oleh
elemen label.
Berikut adalah contoh penggunaan tag helper label.
@model SqlServerDbFirst.Models.GuestBook
Image
Untuk membuat elemen <img> menjadi tag helper dapat dilakukan dengan sintaks berikut
ini.
Berikut ini adalah contoh penggunaan tag helper ini yang nanti dapat dilihat pada halaman
Book/Index.cshtml yang dapat dilihat pada sub bab selanjutnya yaitu sub bab Book Store:
Komponen View.
Tag helper <img> dengan atribut asp-append-version cocok digunakan untuk menampilkan
data yang melibatkan gambar, karena tanpa tambahan atribut tersebut gambar akan diambil
dari cache karena memiliki nama file yang sama. Tetapi dengan penambahan nilai versi di
belakang nama file maka dianggap nama file berbeda, sehingga file gambar diambil dari
kembali dari server.
Form
Untuk membuat elemen <form> menjadi tag helper dengan menggunakan sintaks berikut ini.
<form asp-controller="controller_name"
asp-action="action_name"
asp-anti-forgery="false/true"
asp-route-returnurl="url">
. . .
</form>
Keterangan:
236
- controller_name, nama class controller.
- action_name, nama method action.
- asp-anti-forgery, opsi penggunaan anti forgery.
- url, adalah url redirect untuk kembali.
Atribut-atribut di atas tidak seluruhnya harus digunakan. Implementasinya dapat dilihat
pada contoh di bawah ini.
<form asp-controller="Category" asp-action="Create">
</form>
</form>
Input
Elemen <input> pada tag HTML dapat digunakan untuk beberapa tipe input, yaitu:
- Text untuk input teks.
- Radio button, tipe ini digunakan untuk memilih sebuah nilai dari beberapa
pilihan pilihan nilai yang tersedia.
- Check box bentuk ini digunakan digunakan untuk memilih lebih dari satu nilai
dari beberapa pilihan nilai yang tersedia.
- File, tipe ini digunakan untuk memilih file yang akan diupload.
Tag helper <input> memiliki kemampuan untuk menentukan tipe input secara otomatis
berdasarkan tipe data dari property pada class model. Sebagai contoh dimiliki class model
berikut ini.
ContohModel.cs
using System;
using System.ComponentModel.DataAnnotations;
namespace SqlServerBookStore.Models
{
public partial class ContohModel{
[Display(Name ="Contoh Text")]
public String ContohText{set; get;}
<label asp-for="ContohDateTime"></label>:
237
<input asp-for="ContohDateTime" />
<br />
<label asp-for="ContohNumber"></label>:
<input asp-for="ContohNumber" />
<br />
<label asp-for="ContohBoolean"></label>:
<input asp-for="ContohBoolean" />
<br />
Pada tag helper input digunakan atribut asp-for untuk menentukan property class model
yang ditangani oleh tag helper. Dari contoh di atas dapat dilihat tidak ada penentuan nilai
untuk atribut “type” pada tag <input> seperti umumnya ditemui pada tag HTML. Hasil dari
render HTML contoh tag helper di atas adalah sebagai berikut.
Dari hasil render di atas dapat dilihat secara otomatis telah ditambahkan atribut-atribut pada
setiap elemen input sesuai dengan tipe datanya.
Tag helper input juga dapat membaca atribut pada setiap property pada class model untuk
menentukan tipe input yang akan digunakan. Berikut ini adalah contoh model yang
menggunakan atribut untuk menentukan tipe data untuk property.
ContohAtributModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
238
namespace SqlServerBookStore.Models
{
public class ContohAtributModel
{
[Display(Name = "Contoh Email")]
[EmailAddressAttribute]
public String ContohEmail { set; get; }
}
}
Dan berikut ini adalah contoh penggunaan tag helper input untuk class model di atas.
@model SqlServerBookStore.Models.ContohAtributModel
<label asp-for="ContohUrl"></label>:
<input asp-for="ContohUrl" />
<br />
<label asp-for="ContohPhone"></label>:
<input asp-for="ContohPhone" />
<br />
<label asp-for="ContohPassword"></label>:
<input asp-for="ContohPassword" />
<br />
<label asp-for="ContohDate"></label>:
<input asp-for="ContohDate" />
<br />
<label asp-for="ContohTime"></label>:
<input asp-for="ContohTime" />
<br />
239
Kode di atas akan menghasilkan antarmuka seperti pada gambar di bawah ini.
240
<button type="submit" class="btn btn-success">Submit</button>
</form>
Dari contoh di atas dapat dilihat bagaimana secara otomatis tag helper input memberikan
atribut HTML sesuai dengan atribut property class model.
Walau pada contoh di atas diperlihatkan cara kerja otomatis tag helper input untuk
menentukan nilai atribut type, tetapi developer tetap dapat memberikan nilai atribut type
secara manual. Misalnya dapat dilihat pada contoh di bawah ini.
<label asp-for="ContohPassword"></label>:
<input asp-for="ContohPassword" type="password" />
<label asp-for="ContohText"></label>:
<input asp-for="ContohText" type="radio" value="true"/>
TextArea
Berikut ini adalah sintaks penggunaan tag helper textarea.
<textarea asp-for="property_name"></textarea>
Tag helper textarea di atas akan dirender menjadi tag HTML berikut ini.
Select
Berikut adalah sintaks tag helper select.
<select asp-for="property_name" asp-items="data">
</select>
Keterangan:
- property_name, nama property dari class model yang dikelola oleh tag helper select.
- data, object collection yang berisi data untuk ditampilkan pada elemen select.
Berikut adalah contoh penggunaan tag helper select.
@model SqlServerBookStore.Models.ContohModel
241
</form>
Pada contoh di tas dapat dilihat pada atribut asp-items diisi dengan data dari
ViewBag.Authors. Nilai pada object ViewBag.Authors diisi dari komponen controller dengan
kode berikut ini.
LatihanController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using SqlServerBookStore.Models;
using SqlServerBookStore.Data;
namespace SqlServerBookStore.Controllers
{
public class LatihanController : Controller
{
private readonly ApplicationDbContext _context;
242
Gambar 146. Contoh antarmuka implementasi tag helper select.
Tag helper select di atas dirender menjadi tag HTML berikut ini.
<select id="ContohText" name="ContohText">
<option value="1">Mohammad</option>
<option value="2">Reza</option>
<option value="3">Faisal</option>
</select>
Tag <select> di atas hanya dapat digunakan untuk memilih satu nilai dari daftar nilai yang
disediakan. Jika ingin menggunakan tag <select> agar dapat digunakan untuk memilih lebih
dari satu nilai maka dapat digunakan atribut multiple seperti contoh berikut ini.
<select asp-for="ContohText"
asp-items="@(new SelectList(ViewBag.Authors, "AuthorID", "Name"))"
multiple="multiple">
</select>
Gambar 147. Contoh antarmuka implementasi tag helper select dengan atribut
multiple.
243
Tombol
Untuk membuat tombol submit data dengan tag helper cukup digunakan tag HTML berikut
ini.
<button type="submit">Submit</button>
<button type="reset">Reset</button>
Validasi
Untuk proses validasi, langkah pertama adalah menambahkan baris berikut ini di dalam tag
<form></form>.
<div asp-validation-summary="All"></div>
Pada baris di atas digunakan atribut asp-validation-summary. Nilai yang dapat diberikan
kepada atribut tersebut adalah sebagai berikut:
- All, jika ingin menampilkan pesan validasi pada bagian tag helper “asp-validation-
summary” di atas dan di tag helper “asp-validation-for” di bawah ini.
- ModelOnly, hanya akan menampilkan pesan validasi di bagian tag helper “asp-
validation-for” di bawah ini.
- None, tidak akan melakukan proses validasi.
Tag <span> dapat digunakan untuk menampilkan pesan validasi. Berikut ini adalah sintaks
yang digunakan untuk validasi.
<span asp-validation-for="property_name"></span>
<label asp-for="Name"></label>
<input asp-for="Name">
<span asp-validation-for="Name"></span>
</form>
244
- Delete.cshtml berfungsi untuk menampilkan detail kategori buku yang akan
dihapus.
2. Mengelola pengarang buku, fitur ini akan memiliki 2 file yaitu:
- Index.cshtml yang akan menampilkan tabel daftar pengarang buku. Pada
halaman ini juga terdapat fitur untuk menghapus data pengarang buku.
Pengarang buku hanya bisa dihapus jika belum ada buku yang terkait dengan
data pengarang tersebut.
- Detail.cshtml berfungsi untuk menampilkan data pengarang buku yang dipilih
pada halaman daftar pengarang buku.
- Create.cshtml sebagai form input untuk menambah data pengarang buku.
- Edit.cshtml untuk form mengedit data pengarang buku.
- Delete.cshtml berfungsi untuk menampilkan detail pengarang buku yang akan
dihapus.
3. Mengelola buku
- Index.cshtml yang akan menampilkan tabel daftar buku. Pada halaman ini juga
terdapat fitur untuk menghapus data buku.
- Detail.cshtml berfungsi untuk menampilkan data buku yang dipilih pada
halaman daftar buku.
- Create.cshtml sebagai form input untuk menambah data buku.
- Edit.cshtml untuk form mengedit data buku.
- Delete.cshtml berfungsi untuk menampilkan detail buku yang akan dihapus.
4. Mengelola role
- Index.cshtml berfungsi untuk menampilkan daftar role. Pada halaman ini juga
terdapat fitur untuk menghapus role.
- Detail.cshtml berfungsi untuk menampilkan data role yang dipilih pada halaman
daftar role.
- Create.cshtml sebagai form input untuk menambah role.
- Edit.cshtml untuk form mengedit role yang dipilih.
- Delete.cshtml berfungsi untuk menampilkan detail role yang akan dihapus.
5. Mengelola user
- Index.chsmlt berfungsi untuk menampilkan daftar user. pada halaman ini juga
memiliki fitur untuk mengahapus user yang dipilih.
- Detail.cshtml berfungsi untuk menampilkan data user yang dipilih pada halaman
daftar user.
- Create.cshtml sebagai form input untuk menambah user.
- Edit.cshtml untuk form mengedit user yang dipilih.
- Delete.cshtml berfungsi untuk menampilkan detail user yang akan dihapus.
View Categories
File-file berikut ini menangani antarmuka untuk class CategoriesController. Semua file di
bawah ini disimpan pada folder Views/Categories.
Index.cshtml
Berikut adalah antarmuka untuk menampilkan daftar kategori buku.
245
Gambar 148. View Categories - Index.cshtml.
Berikut adalah kode yang digunakan untuk membuat antarmuka tersebut.
Index.cshtml
@model IEnumerable<SqlServerBookStore.Models.Category>
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Book Category</h3>
</div>
<div class="title_right">
<div class="col-md-5 col-sm-5 col-xs-12 form-group pull-
right top_search">
<div class="input-group">
<input type="text" class="form-
control" placeholder="search for...">
<span class="input-group-btn">
<button class="btn btn-
default" type="button">Go!</button>
</span>
</div>
</div>
</div>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>List of Category</h2>
<ul class="nav navbar-right panel_toolbox">
<li><a asp-controller="Categories" asp-
action="Create"><i class="fa fa-plus"></i> Add Data</a></li>
</ul>
<div class="clearfix"></div>
</div>
<div class="x_content">
<div class="table-responsive">
246
<table class="table table-
striped jambo_table bulk_action">
<thead>
<tr class="headings">
<th class="column-
title" style="width: 5%">@Html.DisplayNameFor(model => model.FirstOrDefault(
).CategoryID)</th>
<th class="column-
title" style="width: 80%">@Html.DisplayNameFor(model => model.FirstOrDefault
().Name)</th>
<th class="column-title no-
link last" style="width: 15%; text-
align:center"><span class="nobr">Action</span></th>
</tr>
</thead>
<tbody>
@{ var odd = false; }
@foreach (var item in Model)
{
<tr class="@(odd ? "odd": "even") pointe
r">
<td class=" ">@item.CategoryID</td>
<td class=" ">@item.Name</td>
<td class=" last">
<a asp-
controller="Categories" asp-action="Details" asp-route-
id="@item.CategoryID">Details</a> |
<a asp-
controller="Categories" asp-action="Edit" asp-route-
id="@item.CategoryID">Edit</a> |
<a asp-
controller="Categories" asp-action="Delete" asp-route-
id="@item.CategoryID">Delete</a>
</td>
</tr>
odd = !odd;
}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
Details.cshtml
Berikut adalah antarmuka untuk menampilkan data kategori buku yang dipilih pada halaman
daftar kategori buku.
247
Gambar 149. View Categories - Details.cshtml.
Berikut adalah kode untuk membuat antarmuka di atas.
Details.cshtml
@model SqlServerBookStore.Models.Category
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Book Category</h3>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>Detail Book Category</h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
<br />
<form asp-controller="Categories" asp-
action="Create" data-parsley-validate class="form-horizontal form-label-
left">
<div asp-validation-summary="All"></div>
<div class="form-group">
<label asp-for="Name" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Name" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="ln_solid"></div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-
md-offset-3">
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Index", "Categor
ies")'">Back to List</button>
248
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Edit", "Categori
es", new { id = @Model.CategoryID})'">Edit</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
Create.cshtml
Berikut adalah antarmuka untuk input data kategori buku.
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Book Category</h3>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>Form Book Category <small>create data</small></h
2>
<div class="clearfix"></div>
</div>
<div class="x_content">
<br />
249
<form asp-controller="Categories" asp-
action="Create" data-parsley-validate class="form-horizontal form-label-
left">
<div asp-validation-summary="All"></div>
<div class="form-group">
<label asp-for="Name" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Name" required="required" class="form-control col-md-7 col-xs-12">
<span asp-validation-for="Name"></span>
</div>
</div>
<div class="ln_solid"></div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-
md-offset-3">
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Index", "Categor
ies")'">Cancel</button>
<button class="btn btn-
primary" type="reset" onclick='document.forms[0].reset();return false;'>Rese
t</button>
<button type="submit" class="btn btn-
success">Submit</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
Edit.cshtml
Berikut ini adalah antarmuka untuk mengedit data kategori buku yang dipilih.
250
Edit.cshtml
@model SqlServerBookStore.Models.Category
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Book Category</h3>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>Form Book Category <small>edit data</small></h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
<br />
<form asp-controller="Categories" asp-
action="Edit" data-parsley-validate class="form-horizontal form-label-left">
<div asp-validation-summary="All"></div>
<input type="hidden" asp-for="CategoryID" />
<div class="form-group">
<label asp-for="Name" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Name" required="required" class="form-control col-md-7 col-xs-12">
<span asp-validation-for="Name"></span>
</div>
</div>
<div class="ln_solid"></div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-
md-offset-3">
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Index", "Categor
ies")'">Cancel</button>
<button type="submit" class="btn btn-
success">Update</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
Delete.cshtml
Berikut adalah antarmuka untuk menampilkan halaman konfirmasi untuk menghapus data
kategori buku yang telah dipilih.
251
Gambar 152. View Categories - Delete.
Berikut adalah kode untuk membuat antarmuka di atas.
Delete.cshtml
@model SqlServerBookStore.Models.Category
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Book Category</h3>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>Are you sure you want to delete this?</h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
<br />
<form asp-controller="Categories" asp-
action="Delete" data-parsley-validate class="form-horizontal form-label-
left">
<div asp-validation-summary="All"></div>
<input type="hidden" asp-for="CategoryID" />
<div class="form-group">
<label asp-for="Name" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Name" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="ln_solid"></div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-
md-offset-3">
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Index", "Categor
ies")'">Back to List</button>
252
<button class="btn btn-
primary" type="submit">Delete</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
View Authors
File-file berikut ini menangani antarmuka untuk class AuthorsController. Semua file di
bawah ini disimpan pada folder Views/Authors.
Index.cshtml
Berikut adalah antarmuka untuk menampilkan daftar pengarang buku.
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Author</h3>
</div>
<div class="title_right">
<div class="col-md-5 col-sm-5 col-xs-12 form-group pull-
right top_search">
<div class="input-group">
<input type="text" class="form-
control" placeholder="search for...">
<span class="input-group-btn">
253
<button class="btn btn-
default" type="button">Go!</button>
</span>
</div>
</div>
</div>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>List of Author</h2>
<ul class="nav navbar-right panel_toolbox">
<li><a asp-controller="Authors" asp-
action="Create"><i class="fa fa-plus"></i> Add Data</a></li>
</ul>
<div class="clearfix"></div>
</div>
<div class="x_content">
<div class="table-responsive">
<table class="table table-
striped jambo_table bulk_action">
<thead>
<tr class="headings">
<th class="column-
title" style="width: 5%">@Html.DisplayNameFor(model => model.AuthorID)</th>
<th class="column-
title" style="width: 40%">@Html.DisplayNameFor(model => model.Name)</th>
<th class="column-
title" style="width: 40%">@Html.DisplayNameFor(model => model.Email)</th>
<th class="column-title no-
link last" style="width: 15%; text-
align:center"><span class="nobr">Action</span></th>
</tr>
</thead>
<tbody>
@{ var odd = false; }
@foreach (var item in Model)
{
<tr class="@(odd ? "odd": "even") pointer">
<td class=" ">@item.AuthorID</td>
<td class=" ">@item.Name</td>
<td class=" ">@item.Email</td>
<td class=" last">
<a asp-controller="Authors" asp-
action="Details" asp-route-id="@item.AuthorID">Details</a> |
<a asp-controller="Authors" asp-
action="Edit" asp-route-id="@item.AuthorID">Edit</a> |
<a asp-controller="Authors" asp-
action="Delete" asp-route-id="@item.AuthorID">Delete</a>
</td>
</tr>
odd = !odd;
}
</tbody>
</table>
254
</div>
</div>
</div>
</div>
</div>
</div>
Details.cshtml
Berikut adalah antarmuka untuk menampilkan data pengarang buku yang dipilih pada
halaman daftar pengarang buku.
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Author</h3>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>Detail Author</h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
<br />
<form asp-controller="Authors" asp-
action="Create" data-parsley-validate class="form-horizontal form-label-
left">
<div asp-validation-summary="All"></div>
<div class="form-group">
255
<label asp-for="Name" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Name" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="form-group">
<label asp-for="Email" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Email" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="ln_solid"></div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-
md-offset-3">
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Index", "Authors
")'">Back to List</button>
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Edit", "Authors"
, new { id = @Model.AuthorID})'">Edit</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
Create.cshtml
Berikut adalah antarmuka untuk input data pengarang buku.
256
Create.cshtml
@model SqlServerBookStore.Models.Author
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Author</h3>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>Form Author <small>create data</small></h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
<br />
<form asp-
controller="Authors" method="POST" enctype="multipart/form-data" asp-
action="Create" data-parsley-validate class="form-horizontal form-label-
left">
<div asp-validation-summary="All"></div>
<div class="form-group">
<label asp-for="Name" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Name" required="required" class="form-control col-md-7 col-xs-12">
<span asp-validation-for="Name"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Email" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Email" required="required" class="form-control col-md-7 col-xs-12">
<span asp-validation-for="Email"></span>
</div>
</div>
<div class="ln_solid"></div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-
md-offset-3">
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Index", "Authors
")'">Cancel</button>
<button class="btn btn-
primary" type="reset" onclick='document.forms[0].reset();return false;'>Rese
t</button>
<button type="submit" class="btn btn-
success">Submit</button>
</div>
</div>
</form>
</div>
</div>
</div>
257
</div>
</div>
</div>
Edit.cshtml
Berikut ini adalah antarmuka untuk mengedit data pengarang buku yang dipilih.
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Author</h3>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>Form Author<small>edit data</small></h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
<br />
<form asp-controller="Authors" asp-
action="Edit" data-parsley-validate class="form-horizontal form-label-left">
<div asp-validation-summary="All"></div>
<input type="hidden" asp-for="AuthorID" />
<div class="form-group">
<label asp-for="Name" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
258
<input asp-
for="Name" required="required" class="form-control col-md-7 col-xs-12">
<span asp-validation-for="Name"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Email" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Email" required="required" class="form-control col-md-7 col-xs-12">
<span asp-validation-for="Email"></span>
</div>
</div>
<div class="ln_solid"></div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-
md-offset-3">
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Index", "Authors
")'">Cancel</button>
<button type="submit" class="btn btn-
success">Update</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
Delete.cshtml
Berikut adalah antarmuka untuk menampilkan halaman konfirmasi untuk menghapus data
pengarang buku yang telah dipilih.
259
Berikut adalah kode untuk membuat antarmuka di atas.
Delete.cshtml
@model SqlServerBookStore.Models.Author
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Author</h3>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>Are you sure you want to delete this?</h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
<br />
<form asp-controller="Authors" asp-
action="Delete" data-parsley-validate class="form-horizontal form-label-
left">
<div asp-validation-summary="All"></div>
<input type="hidden" asp-for="AuthorID" />
<div class="form-group">
<label asp-for="Name" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Name" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="form-group">
<label asp-for="Email" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Email" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="ln_solid"></div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-
md-offset-3">
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Index", "Authors
")'">Back to List</button>
<button class="btn btn-
primary" type="submit">Delete</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
260
View Books
File-file berikut ini menangani antarmuka untuk class BooksController. Semua file di bawah
ini disimpan pada folder Views/Books.
Index.cshtml
Berikut adalah antarmuka untuk menampilkan daftar buku.
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Book</h3>
</div>
<div class="title_right">
<div class="col-md-5 col-sm-5 col-xs-12 form-group pull-
right top_search">
<div class="input-group">
<input type="text" class="form-
control" placeholder="search for...">
<span class="input-group-btn">
<button class="btn btn-
default" type="button">Go!</button>
</span>
</div>
</div>
</div>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
261
<h2>List of Book</h2>
<ul class="nav navbar-right panel_toolbox">
<li><a asp-controller="Books" asp-
action="Create"><i class="fa fa-plus"></i> Add Data</a></li>
</ul>
<div class="clearfix"></div>
</div>
<div class="x_content">
<div class="table-responsive">
<table class="table table-
striped jambo_table bulk_action">
<thead>
<tr class="headings">
<th class="column-
title" style="width: 10%">Cover</th>
<th class="column-
title" style="width: 10%">Category</th>
<th class="column-
title" style="width: 35%">Title</th>
<th class="column-
title" style="width: 20%">Publish Date</th>
<th class="column-
title" style="width: 10%">Qty</th>
<th class="column-title no-
link last" style="width: 15%"><span class="nobr">Action</span></th>
</tr>
</thead>
<tbody>
@{ var odd = false; }
@foreach (var item in Model)
{
<tr class="@(odd ? "odd": "even") pointe
r">
<td class=" "><img src="~/upload/@(i
tem.ISBN).jpg" asp-append-
version="true" style="width: 100px; height: 142px" /></td>
<td class=" ">@item.CategoryName</td
>
<td class=" ">
@item.Title<br />
ISBN: @item.ISBN<br />
Authors: @item.AuthorNames<br />
Price: @item.Price<br />
</td>
<td class=" ">@item.PublishDate</td>
<td class=" ">@item.Quantity</td>
<td class=" last">
<a asp-controller="Books" asp-
action="Details" asp-route-id="@item.ISBN">Details</a> |
<a asp-controller="Books" asp-
action="Edit" asp-route-id="@item.ISBN">Edit</a> |
<a asp-controller="Books" asp-
action="Delete" asp-route-id="@item.ISBN">Delete</a>
</td>
</tr>
odd = !odd;
}
</tbody>
</table>
262
</div>
</div>
</div>
</div>
</div>
</div>
Details.cshtml
Berikut adalah antarmuka untuk menampilkan data buku yang dipilih pada halaman daftar
buku.
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Book</h3>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>Detail Book</h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
<br />
<form data-parsley-validate class="form-
horizontal form-label-left">
<div class="form-group">
<label class="control-label col-md-3 col-sm-
3 col-xs-12">Cover</label>
<div class="col-md-6 col-sm-6 col-xs-12">
263
<img src="~/upload/@(Model.ISBN).jpg" as
p-append-version="true" style="width: 100px; height: 142px" />
</div>
</div>
<div class="form-group">
<label asp-for="ISBN" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="ISBN" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="form-group">
<label asp-
for="CategoryName" class="control-label col-md-3 col-sm-3 col-xs-
12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="CategoryName" readonly="readonly" class="form-control col-md-7 col-xs-
12">
</div>
</div>
<div class="form-group">
<label asp-for="Title" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Title" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="form-group">
<label asp-for="AuthorNames" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="AuthorNames" readonly="readonly" class="form-control col-md-7 col-xs-
12">
</div>
</div>
<div class="form-group">
<label asp-for="PublishDate" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="PublishDate" readonly="readonly" class="form-control col-md-7 col-xs-
12">
</div>
</div>
<div class="form-group">
<label asp-for="Price" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Price" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="form-group">
<label asp-for="Quantity" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
264
<input asp-
for="Quantity" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="ln_solid"></div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-
md-offset-3">
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Index", "Books")
'">Back to List</button>
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Edit", "Books",
new { id = @Model.ISBN})'">Edit</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
Create.cshtml
Berikut adalah antarmuka untuk input data buku.
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Book</h3>
</div>
<div class="clearfix"></div>
265
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>Form of Book <small>create data</small></h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
<br />
<form method="POST" enctype="multipart/form-
data" asp-controller="Books" asp-action="Create" data-parsley-
validate class="form-horizontal form-label-left">
<div asp-validation-summary="All"></div>
<div class="form-group">
<label asp-for="ISBN" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="ISBN" required="required" class="form-control col-md-7 col-xs-12">
<span asp-validation-for="ISBN"></span>
</div>
</div>
<div class="form-group">
<label asp-for="CategoryID" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-9 col-sm-9 col-xs-12">
<select asp-for="CategoryID" asp-
items="@ViewBag.Categories" class="form-control">
<option>Choose Category</option>
</select>
<span asp-validation-
for="CategoryID"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Title" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Title" required="required" class="form-control col-md-7 col-xs-12">
<span asp-validation-for="Title"></span>
</div>
</div>
<div class="form-group">
<label asp-for="AuthorIDs" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-9 col-sm-9 col-xs-12">
<select asp-for="AuthorIDs" asp-
items="@ViewBag.Authors" class="select2_multiple form-
control" multiple="multiple"></select>
<span asp-validation-
for="AuthorIDs"></span>
</div>
</div>
<div class="form-group">
<label asp-for="PublishDate" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="PublishDate" required="required" class="form-control col-md-7 col-xs-
12">
266
<span asp-validation-
for="PublishDate"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Price" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Price" required="required" class="form-control col-md-7 col-xs-12">
<span asp-validation-for="Price"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Quantity" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Quantity" required="required" class="form-control col-md-7 col-xs-12">
<span asp-validation-
for="Quantity"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Photo" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Photo" type="file" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="ln_solid"></div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-
md-offset-3">
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Index", "Books")
'">Cancel</button>
<button class="btn btn-
primary" type="reset" onclick='document.forms[0].reset();return false;'>Rese
t</button>
<button type="submit" class="btn btn-
success">Submit</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
Edit.cshtml
Berikut ini adalah antarmuka untuk mengedit data buku yang dipilih.
267
Gambar 161. View Books - Edit.
Berikut adalah kode untuk membuat antarmuka di atas.
Edit.cshtml
@model SqlServerBookStore.Models.BookFormViewModel
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Book</h3>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>Form of Book <small>edit data</small></h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
<br />
<form method="POST" enctype="multipart/form-
data" asp-controller="Books" asp-action="Edit" data-parsley-
validate class="form-horizontal form-label-left">
<div asp-validation-summary="All"></div>
<input type="hidden" asp-for="ISBN" />
<div class="form-group">
<label asp-for="ISBN" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="ISBN" readonly="readonly" required="required" class="form-control col-
md-7 col-xs-12">
<span asp-validation-for="ISBN"></span>
</div>
</div>
<div class="form-group">
<label asp-for="CategoryID" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-9 col-sm-9 col-xs-12">
268
<select asp-for="CategoryID" asp-
items="@ViewBag.Categories" class="form-control">
<option>Choose Category</option>
</select>
<span asp-validation-
for="CategoryID"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Title" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Title" required="required" class="form-control col-md-7 col-xs-12">
<span asp-validation-for="Title"></span>
</div>
</div>
<div class="form-group">
<label asp-for="AuthorIDs" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-9 col-sm-9 col-xs-12">
<select asp-for="AuthorIDs" asp-
items="@ViewBag.Authors" class="select2_multiple form-
control" multiple="multiple"></select>
<span asp-validation-
for="AuthorIDs"></span>
</div>
</div>
<div class="form-group">
<label asp-for="PublishDate" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="PublishDate" required="required" class="form-control col-md-7 col-xs-
12">
<span asp-validation-
for="PublishDate"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Price" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Price" required="required" class="form-control col-md-7 col-xs-12">
<span asp-validation-for="Price"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Quantity" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Quantity" required="required" class="form-control col-md-7 col-xs-12">
<span asp-validation-
for="Quantity"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Photo" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
269
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Photo" type="file" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="ln_solid"></div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-
md-offset-3">
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Index", "Books")
'">Cancel</button>
<button type="submit" class="btn btn-
success">Update</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
Delete.cshtml
Berikut adalah antarmuka untuk menampilkan halaman konfirmasi untuk menghapus data
buku yang telah dipilih.
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Book</h3>
</div>
<div class="clearfix"></div>
270
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>Are you sure you want to delete this?</h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
<br />
<form asp-controller="Books" asp-
action="Delete" data-parsley-validate class="form-horizontal form-label-
left">
<input type="hidden" asp-for="ISBN" />
<div class="form-group">
<label class="control-label col-md-3 col-sm-
3 col-xs-12">Cover</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<img src="~/upload/@(Model.ISBN).jpg" as
p-append-version="true" style="width: 100px; height: 142px" />
</div>
</div>
<div class="form-group">
<label asp-for="ISBN" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="ISBN" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="form-group">
<label asp-
for="CategoryName" class="control-label col-md-3 col-sm-3 col-xs-
12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="CategoryName" readonly="readonly" class="form-control col-md-7 col-xs-
12">
</div>
</div>
<div class="form-group">
<label asp-for="Title" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Title" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="form-group">
<label asp-for="AuthorNames" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="AuthorNames" readonly="readonly" class="form-control col-md-7 col-xs-
12">
</div>
</div>
<div class="form-group">
<label asp-for="PublishDate" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
271
<input asp-
for="PublishDate" readonly="readonly" class="form-control col-md-7 col-xs-
12">
</div>
</div>
<div class="form-group">
<label asp-for="Price" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Price" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="form-group">
<label asp-for="Quantity" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Quantity" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="ln_solid"></div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-
md-offset-3">
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Index", "Books")
'">Back to List</button>
<button class="btn btn-
primary" type="submit">Delete</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
272
View Role
File-file berikut ini menangani antarmuka untuk class RoleController. Semua file di bawah
ini disimpan pada folder Views/Role.
Index.cshtml
Berikut adalah antarmuka untuk menampilkan daftar role.
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Roles</h3>
</div>
<div class="title_right">
<div class="col-md-5 col-sm-5 col-xs-12 form-group pull-
right top_search">
<div class="input-group">
<input type="text" class="form-
control" placeholder="Search for...">
<span class="input-group-btn">
<button class="btn btn-
default" type="button">Go!</button>
</span>
</div>
</div>
</div>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
273
<h2>List of Role</h2>
<ul class="nav navbar-right panel_toolbox">
<li><a asp-controller="Role" asp-
action="Create"><i class="fa fa-plus"></i> Add Data</a></li>
</ul>
<div class="clearfix"></div>
</div>
<div class="x_content">
<div class="table-responsive">
<table class="table table-
striped jambo_table bulk_action">
<thead>
<tr class="headings">
<th class="column-
title" style="width: 25%">@Html.DisplayNameFor(model => model.FirstOrDefault
().RoleID)</th>
<th class="column-
title" style="width: 30%">@Html.DisplayNameFor(model => model.FirstOrDefault
().RoleName)</th>
<th class="column-
title" style="width: 30%">@Html.DisplayNameFor(model => model.FirstOrDefault
().Description)</th>
<th class="column-title no-
link last" style="width: 15%;text-
align:center"><span class="nobr">Action</span></th>
</tr>
</thead>
<tbody>
@{ var odd = false; }
@foreach (var item in Model)
{
<tr class="@(odd ? "odd": "even") pointe
r">
<td class=" ">@item.RoleID</td>
<td class=" ">@item.RoleName</td>
<td class=" ">@item.Description</td>
<td class=" last">
<a asp-controller="Role" asp-
action="Detail" asp-route-id="@item.RoleID">Detail</a> |
<a asp-controller="Role" asp-
action="Edit" asp-route-id="@item.RoleID">Edit</a> |
<a asp-controller="Role" asp-
action="Delete" asp-route-id="@item.RoleID">Delete</a>
</td>
</tr>
odd = !odd;
}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
274
Detail.cshtml
Berikut adalah antarmuka untuk menampilkan data role yang dipilih pada halaman daftar
role.
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Roles</h3>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>Form of Role <small>edit data</small></h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
<br />
<form data-parsley-validate class="form-
horizontal form-label-left">
<div asp-validation-summary="All"></div>
<div class="form-group">
<label asp-for="RoleID" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="RoleID" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="form-group">
<label asp-for="RoleName" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
275
<input asp-
for="RoleName" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="form-group">
<label asp-for="Description" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Description" readonly="readonly" class="form-control col-md-7 col-xs-
12">
</div>
</div>
<div class="ln_solid"></div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-
md-offset-3">
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Index", "Role")'
">Back to List</button>
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Edit", "Role", n
ew { id = @Model.RoleID})'">Edit</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
Create.cshtml
Berikut adalah antarmuka untuk input data role.
276
Berikut adalah kode untuk membuat antarmuka di atas.
Create.cshtml
@model SqlServerBookStore.Models.RoleViewModel
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Roles</h3>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>Form of Role <small>create data</small> </h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
<br />
<form asp-controller="Role" asp-
action="Create" data-parsley-validate class="form-horizontal form-label-
left">
<div asp-validation-summary="All"></div>
<div class="form-group">
<label asp-for="RoleID" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="RoleID" required="required" class="form-control col-md-7 col-xs-12">
<span asp-validation-
for="RoleID"></span>
</div>
</div>
<div class="form-group">
<label asp-for="RoleName" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="RoleName" required="required" class="form-control col-md-7 col-xs-12">
<span asp-validation-
for="RoleName"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Description" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Description" required="required" class="form-control col-md-7 col-xs-
12">
<span asp-validation-
for="Description"></span>
</div>
</div>
<div class="ln_solid"></div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-
md-offset-3">
277
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Index", "Role")'
">Cancel</button>
<button class="btn btn-
primary" type="reset" onclick='document.forms[0].reset();return false;'>Rese
t</button>
<button type="submit" class="btn btn-
success">Submit</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
Edit.cshtml
Berikut ini adalah antarmuka untuk mengedit data role yang dipilih.
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Roles</h3>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>Form of Role <small>edit data</small></h2>
<div class="clearfix"></div>
278
</div>
<div class="x_content">
<br />
<form asp-controller="Role" asp-action="Edit" data-
parsley-validate class="form-horizontal form-label-left">
<div asp-validation-summary="All"></div>
<div class="form-group">
<label asp-for="RoleID" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="RoleID" required="required" readonly="readonly" class="form-
control col-md-7 col-xs-12">
<span asp-validation-
for="RoleID"></span>
</div>
</div>
<div class="form-group">
<label asp-for="RoleName" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="RoleName" required="required" class="form-control col-md-7 col-xs-12">
<span asp-validation-
for="RoleName"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Description" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Description" required="required" class="form-control col-md-7 col-xs-
12">
<span asp-validation-
for="Description"></span>
</div>
</div>
<div class="ln_solid"></div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-
md-offset-3">
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Index", "Role")'
">Cancel</button>
<button type="submit" class="btn btn-
success">Update</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
279
Delete.cshtml
Berikut adalah antarmuka untuk menampilkan halaman konfirmasi untuk menghapus data
role yang telah dipilih.
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Roles</h3>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>Are you sure you want to delete this?</h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
<br />
<form asp-controller="Role" asp-
action="Delete" data-parsley-validate class="form-horizontal form-label-
left">
<div asp-validation-summary="All"></div>
<input type="hidden" asp-for="RoleID" />
<div class="form-group">
<label asp-for="RoleID" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="RoleID" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="form-group">
280
<label asp-for="RoleName" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="RoleName" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="form-group">
<label asp-for="Description" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Description" readonly="readonly" class="form-control col-md-7 col-xs-
12">
</div>
</div>
<div class="ln_solid"></div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-
md-offset-3">
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Index", "Role")'
">Back to List</button>
<button class="btn btn-
primary" type="submit">Delete</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
281
View User
File-file berikut ini menangani antarmuka untuk class UserController. Semua file di bawah
ini disimpan pada folder Views/User.
Index.cshtml
Berikut adalah antarmuka untuk menampilkan daftar user.
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Users</h3>
</div>
<div class="title_right">
<div class="col-md-5 col-sm-5 col-xs-12 form-group pull-
right top_search">
<div class="input-group">
<input type="text" class="form-
control" placeholder="Search for...">
<span class="input-group-btn">
<button class="btn btn-
default" type="button">Go!</button>
</span>
</div>
</div>
</div>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
282
<h2>List of User</h2>
<ul class="nav navbar-right panel_toolbox">
<li><a asp-controller="User" asp-
action="Create"><i class="fa fa-plus"></i> Add Data</a></li>
</ul>
<div class="clearfix"></div>
</div>
<div class="x_content">
<div class="table-responsive">
<table class="table table-
striped jambo_table bulk_action">
<thead>
<tr class="headings">
<th class="column-
title" style="width: 25%">@Html.DisplayNameFor(model => model.FirstOrDefault
().UserName)</th>
<th class="column-
title" style="width: 20%">@Html.DisplayNameFor(model => model.FirstOrDefault
().RoleName)</th>
<th class="column-
title" style="width: 20%">@Html.DisplayNameFor(model => model.FirstOrDefault
().Email)</th>
<th class="column-
title" style="width: 20%">@Html.DisplayNameFor(model => model.FirstOrDefault
().FullName)</th>
<th class="column-title no-
link last" style="width: 15%;text-
align:center"><span class="nobr">Action</span></th>
</tr>
</thead>
<tbody>
@{ var odd = false; }
@foreach (var item in Model)
{
<tr class="@(odd ? "odd": "even") pointe
r">
<td class=" ">@item.UserName</td>
<td class=" ">@item.RoleName</td>
<td class=" ">@item.Email</td>
<td class=" ">@item.FullName</td>
<td class=" last">
<a asp-controller="User" asp-
action="Detail" asp-route-id="@item.UserName">Detail</a> |
<a asp-controller="User" asp-
action="Edit" asp-route-id="@item.UserName">Edit</a> |
<a asp-controller="User" asp-
action="Delete" asp-route-id="@item.UserName">Delete</a>
</td>
</tr>
odd = !odd;
}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
283
Detail.cshtml
Berikut adalah antarmuka untuk menampilkan data user yang dipilih pada halaman daftar
user.
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Users</h3>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>Detail of User</h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
<br />
<form asp-controller="User" asp-action="Edit" data-
parsley-validate class="form-horizontal form-label-left">
<div asp-validation-summary="All"></div>
<div class="form-group">
<label asp-for="UserName" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="UserName" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="form-group">
<label asp-for="RoleName" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
284
<input asp-
for="RoleName" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="form-group">
<label asp-for="Email" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Email" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="form-group">
<label asp-for="FullName" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="FullName" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="ln_solid"></div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-
md-offset-3">
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Index", "User")'
">Back to List</button>
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Edit", "User", n
ew { id = @Model.UserName})'">Edit</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
Create.cshtml
Berikut adalah antarmuka untuk input data user.
285
Gambar 170. View User - Create.cshtml
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Users</h3>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>Form of User <small>create data</small></h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
<br />
<form asp-controller="User" asp-
action="Create" data-parsley-validate class="form-horizontal form-label-
left">
<div asp-validation-summary="All"></div>
<div class="form-group">
<label asp-for="UserName" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="UserName" required="required" class="form-control col-md-7 col-xs-12">
<span asp-validation-
for="UserName"></span>
</div>
</div>
<div class="form-group">
286
<label asp-for="RoleID" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-9 col-sm-9 col-xs-12">
<select asp-for="RoleID" asp-
items="@ViewBag.Roles" class="select2_multiple form-
control" multiple="multiple"></select>
<span asp-validation-
for="RoleID"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Password" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Password" required="required" class="form-control col-md-7 col-xs-12">
<span asp-validation-
for="Password"></span>
</div>
</div>
<div class="form-group">
<label asp-
for="PasswordConfirm" class="control-label col-md-3 col-sm-3 col-xs-
12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="PasswordConfirm" required="required" class="form-control col-md-7 col-
xs-12">
<span asp-validation-
for="PasswordConfirm"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Email" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Email" required="required" class="form-control col-md-7 col-xs-12">
<span asp-validation-for="Email"></span>
</div>
</div>
<div class="form-group">
<label asp-for="FullName" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="FullName" required="required" class="form-control col-md-7 col-xs-12">
<span asp-validation-
for="FullName"></span>
</div>
</div>
<div class="ln_solid"></div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-
md-offset-3">
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Index", "User")'
">Cancel</button>
<button class="btn btn-
primary" type="reset" onclick='document.forms[0].reset();return false;'>Rese
t</button>
287
<button type="submit" class="btn btn-
success">Submit</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
Edit.cshtml
Berikut ini adalah antarmuka untuk mengedit data user yang dipilih.
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Users</h3>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>Form of User <small>edit data</small></h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
<br />
<form asp-controller="User" asp-action="Edit" data-
parsley-validate class="form-horizontal form-label-left">
<div asp-validation-summary="All"></div>
288
<div class="form-group">
<label asp-for="UserName" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="UserName" required="required" readonly="readonly" class="form-
control col-md-7 col-xs-12">
<span asp-validation-
for="UserName"></span>
</div>
</div>
<div class="form-group">
<label asp-for="RoleID" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-9 col-sm-9 col-xs-12">
<select asp-for="RoleID" asp-
items="@ViewBag.Roles" class="select2_multiple form-
control" multiple="multiple"></select>
<span asp-validation-
for="RoleID"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Email" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Email" required="required" class="form-control col-md-7 col-xs-12">
<span asp-validation-for="Email"></span>
</div>
</div>
<div class="form-group">
<label asp-for="FullName" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="FullName" required="required" class="form-control col-md-7 col-xs-12">
<span asp-validation-
for="FullName"></span>
</div>
</div>
<div class="ln_solid"></div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-
md-offset-3">
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Index", "User")'
">Cancel</button>
<button type="submit" class="btn btn-
success">Update</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
289
Delete.cshtml
Berikut adalah antarmuka untuk menampilkan halaman konfirmasi untuk menghapus data
user yang telah dipilih.
<div class="">
<div class="page-title">
<div class="title_left">
<h3>Users</h3>
</div>
<div class="clearfix"></div>
<div class="row">
<div class="col-md-12 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>Are you sure you want to delete this?</h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
<br />
<form asp-controller="User" asp-
action="Delete" data-parsley-validate class="form-horizontal form-label-
left">
<div asp-validation-summary="All"></div>
<input type="hidden" asp-for="UserName" />
<div class="form-group">
<label asp-for="UserName" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="UserName" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
290
</div>
<div class="form-group">
<label asp-for="RoleName" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="RoleName" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="form-group">
<label asp-for="Email" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="Email" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="form-group">
<label asp-for="FullName" class="control-
label col-md-3 col-sm-3 col-xs-12"></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input asp-
for="FullName" readonly="readonly" class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="ln_solid"></div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-
md-offset-3">
<button class="btn btn-
primary" type="button" onclick="location.href='@Url.Action("Index", "User")'
">Back to List</button>
<button class="btn btn-
primary" type="submit">Delete</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
291
8
Implementasi Keamanan
Pada bab ini akan dilakukan pengamanan aplikasi dengan cara yang umum dilakukan yaitu
dengan integrasi sistem pemeriksaan otentikasi dengan menggunakan halaman login.
Selanjutnya adalah integrasi sistem otorisasi yang berfungsi untuk menentukan akses suatu
halaman agar hanya dapat diakses oleh user yang telah ditentukan.
Modifikasi Startup.cs
Fungsi utama dari proses otentikasi adalah user dapat melakukan login untuk memasuki
sistem dan logout untuk keluar dari sistem. Langkah yang pertama untuk implementasi
proses otentikasi adalah menentukan method action yang akan digunakan untuk login dan
logout.
Sedangkan fungsi utama proses otorisasi adalah memberikan pesan kepada user yang tidak
memiliki hak mengakses suatu halaman atau suatu method action. Pesan dapat disampaikan
dengan mengiriman user tersebut ke suatu halaman atau method action.
Untuk menentukan method action yang akan digunakan untuk login, logout dan pesan
penolakan hak akses digunakan penambahan kode pada method ConfigureServices di dalam
file Startup.cs seperti yang terlihat pada baris yang dicetak tebal.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConne
ction")));
services.AddAuthentication(o => {
o.DefaultAuthenticateScheme = CookieAuthenticationDefaults.Authentic
ationScheme; })
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, o =>
{
o.LoginPath = new PathString("/account/login/");
o.LogoutPath = new PathString("/Home/Logout");
o.AccessDeniedPath = new PathString("/Home/AccessDenied");
}
);
292
services.AddMvc();
}
Otentikasi
Otentikasi atau authentication adalah proses verifikasi user mempunyai hak untuk
mengakses aplikasi. Biasanya proses ini melibatkan username dan password. Pada buku ini
proses otentikasi dilakukan dengan bantuan ASP.NET Core Identity.
Model: UserLoginFormViewModel.cs
Model UserLoginFormViewModel digunakan untuk pengiriman data dari komponen view
yang berfungsi sebagai form login ke komponen controller yang akan melakukan proses
otentikasi.
Berikut ini adalah kode dari file UserLoginFormViewModel.cs
UserLoginFormViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
namespace SqlServerBookStore.Models
{
public class UserLoginFormViewModel
{
[Display(Name = "Username")]
[Required(ErrorMessage = "{0} harus diisi.")]
public String UserName { set; get; }
[Display(Name = "Password")]
[Required(ErrorMessage = "{0} harus diisi.")]
[DataType(DataType.Password)]
public String Password { set; get; }
}
}
View
Untuk komponen view akan dibuat dua file yaitu Login.cshtml dan AccessDenied.cshtml.
Login.cshtml
Komponen view Login.cshtml ini digunakan sebagai form untuk login yang memungkinkan
user memasukkan nilai username dan password. Berikut adalah kode lengkap dari file
Views/Home/Login.cshtml.
Login.cshtml
@{
Layout = null;
}
@model SqlServerBookStore.Models.UserLoginFormViewModel
293
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<!-- Meta, title, CSS, favicons, etc. -->
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<body class="login">
<div>
<a class="hiddenanchor" id="signup"></a>
<a class="hiddenanchor" id="signin"></a>
<div class="login_wrapper">
<div class="animate form login_form">
<section class="login_content">
<form asp-controller="Home" asp-action="Login">
<h1><i class="fa fa-book"></i> Book Store</h1>
<div>
<input asp-for="UserName" class="form-
control" placeholder="Username" required="" />
</div>
<div>
<input asp-for="Password" class="form-
control" placeholder="Password" required="" />
</div>
<div>
<button type="submit" class="btn btn-
success">Login</button>
</div>
<div class="clearfix"></div>
<div class="separator">
<div class="clearfix"></div>
<br />
<div>
<p>©2016 All Rights Reserved. Gentelella Ale
la! is a Bootstrap 3 template. Privacy and Terms</p>
</div>
</div>
294
</form>
</section>
</div>
</div>
</div>
</body>
</html>
Pada kode di atas dapat dilihat kode berikut ini. Kode ini berfungsi untuk menyatakan
halaman ini tidak akan menggunakan layout yang telah ada, yaitu _Layout.cshtml.
@{
Layout = null;
}
Selanjutnya digunakan komponen form, input dan button sebagai form login.
. . .
<form asp-controller="Home" asp-action="Login">
<h1><i class="fa fa-book"></i> Book Store</h1>
<div>
<input asp-for="UserName" class="form-control" placeholder="Username"
required="" />
</div>
<div>
<input asp-for="Password" class="form-control" placeholder="Password"
required="" />
</div>
<div>
<button type="submit" class="btn btn-success">Login</button>
</div>
. . .
</form>
. . .
Pada kode di atas dapat dilihat proses login akan ditangani oleh method action Login pada
HomeController.
Berikut ini adalah tampilan dari form login.
295
Gambar 173. Implementasi Keamanan - Form Login.
AccessDenied.cshtml
Berikut adalah isi halaman AccessDenied.cshtml.
AccessDenied.cshtml
<div class="">
<h2>Anda tidak memiliki hak akses ke halaman tersebut.</h2>
</div>
Controller: HomeController
Berikut ini adalah kode lengkap class HomeController.
HomeController.cs
using System;
using System.Collections.Generic;
using System.Linq;
296
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using SqlServerBookStore.Models;
namespace SqlServerBookStore.Controllers
{
[Authorize]
public class HomeController : Controller
{
private readonly SignInManager<ApplicationUser> _signInManager;
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> Login(string returnUrl = null)
{
// Clear the existing external cookie to ensure a clean login pr
ocess
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme)
;
ViewData["ReturnUrl"] = returnUrl;
return View();
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(UserLoginFormViewModel item,
string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
var result = await _signInManager.PasswordSignInAsync(item.U
serName, item.Password, isPersistent: false, lockoutOnFailure: false);
if (result.Succeeded)
{
return RedirectToAction("Index");
}
}
return View();
297
}
[HttpGet]
public async Task<IActionResult> Logout()
{
await _signInManager.SignOutAsync();
return RedirectToAction("Login");
}
[HttpGet]
public IActionResult AccessDenied()
{
return View();
}
}
}
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
Jika proses login berhasil, maka user akan diantarkan ke halaman Index.cshtml dengan cara
memanggil method action Index.
await _signInManager.SignOutAsync();
Sedangkan untuk proses logout dipanggil oleh link yang ada pada _Layout.cshtml.
<a data-toggle="tooltip" data-placement="top" title="Logout" asp-
controller="Home" asp-action="Logout">
<span class="glyphicon glyphicon-off" aria-hidden="true"></span>
</a>
298
Method Action [HttpGet] AccessDenied
Method ini berfungsi untuk menampilkan halaman AccessDenied.cshtml. Proses penentuan
seorang user yang tidak berhak akan diantarkan ke halaman ini dapat dilihat pada setting
yang telah dilakukan pada file Startup.cs yang telah dilakukan pada sub bab di atas.
Otorisasi
Pada sub bab di atas sudah dijelaskan penggunaan atribut [Authorize] dan
[AllowAnonymous]. Kedua atribut ini adalah merupakan komponen utama pada proses
otorisasi. Untuk menggunakan atribut tersebut pada class controller perlu ditambahkan
namespace berikut ini.
using Microsoft.AspNetCore.Authorization;
Untuk mengetahui lebih lanjut pemanfaatan kedua atribut tersebut pada proses otorisasi,
maka akan dilakukan untuk menyelesaikan kasus proses otorisasi pada aplikasi Book Store.
Aplikasi ini memiliki 5 fitur utama untuk mengelola:
1. Kategori buku yang menggunakan CategoriesController.
2. Pengarang buku yang menggunakan AuthorsController.
3. Buku yang menggunakan BooksController.
4. Role yang menggunakan RoleController.
5. User yang menggunakan UserController.
Kelima fitur itu akan dibagi dua untuk diakses oleh 2 role, yaitu:
1. admin.
2. user.
299
using SqlServerBookStore.Models;
namespace SqlServerBookStore.Controllers
{
[Authorize(Roles = "user")]
public class CategoriesController : Controller
{
. . .
}
. . .
}
AuthorsController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Authorization;
using SqlServerBookStore.Data;
using SqlServerBookStore.Models;
namespace SqlServerBookStore.Controllers
{
[Authorize(Roles = "user")]
public class AuthorsController : Controller
{
. . .
}
. . .
}
BooksController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Authorization;
using SqlServerBookStore.Data;
using SqlServerBookStore.Models;
namespace SqlServerBookStore.Controllers
{
[Authorize(Roles = "user")]
public class BooksController : Controller
{
. . .
}
. . .
}
RoleController.cs
using System;
using System.Collections.Generic;
300
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Authorization;
using SqlServerBookStore.Models;
using SqlServerBookStore.Data;
namespace SqlServerBookStore.Controllers
{
[Authorize(Roles = "admin")]
public class RoleController : Controller
{
. . .
}
. . .
}
UserController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Authorization;
using SqlServerBookStore.Models;
using SqlServerBookStore.Data;
namespace SqlServerBookStore.Controllers
{
[Authorize(Roles = "admin")]
public class UserController : Controller
{
. . .
}
. . .
}
Dari kode di atas dapat dilihat penggunaan atribut [Authorize] untuk menentukan role yang
dapat mengakses method action pada class controller. Berikut adalah sintaks penggunaan
atribut ini.
[Authorize]
Atau
Dari sintaks di atas dapat dilihat nilai parameter Roles dapat berisi satu nama role atau lebih.
Atribut ini juga dapat digunakan langsung di atas method action yang diinginkan. Sebagai
contoh jika ingin agar method action Index pada class RoleController dapat diakses oleh role
user maka dapat dilakukan modifikasi sebagai berikut.
RoleController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
301
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Authorization;
using SqlServerBookStore.Models;
using SqlServerBookStore.Data;
namespace SqlServerBookStore.Controllers
{
public class RoleController : Controller
{
private readonly RoleManager<ApplicationRole> db;
[HttpGet]
[Authorize(Roles = "admin, user")]
public IActionResult Index()
{
return View(items);
}
[HttpGet]
[Authorize(Roles = "admin, user")]
public async Task<IActionResult> Detail(string id)
{
RoleViewModel item = new RoleViewModel();
ApplicationRole role = await db.FindByIdAsync(id);
if (role != null)
{
item.RoleID = role.Id;
item.RoleName = role.Name;
item.Description = role.Description;
}
return View(item);
}
[HttpGet]
[Authorize(Roles = "admin")]
public IActionResult Create()
{
return View();
}
[HttpPost]
[Authorize(Roles = "admin")]
public async Task<IActionResult> Create(RoleViewModel item)
{
if (ModelState.IsValid)
{
302
ApplicationRole role = new ApplicationRole();
role.Id = item.RoleID;
role.Name = item.RoleName;
role.Description = item.Description;
return RedirectToAction("Index");
}
return View();
}
[HttpGet]
[Authorize(Roles = "admin")]
public async Task<IActionResult> Edit(string id)
{
RoleViewModel item = new RoleViewModel();
ApplicationRole role = await db.FindByIdAsync(id);
if (role != null)
{
item.RoleID = role.Id;
item.RoleName = role.Name;
item.Description = role.Description;
}
return View(item);
}
[HttpPost]
[Authorize(Roles = "admin")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit([Bind("RoleID,RoleName,Descrip
tion")] RoleViewModel item)
{
if (ModelState.IsValid)
{
ApplicationRole role = await db.FindByIdAsync(item.RoleID);
if (role != null)
{
role.Id = item.RoleID;
role.Name = item.RoleName;
role.Description = item.Description;
var result = await db.UpdateAsync(role);
}
return RedirectToAction("Index");
}
return View();
}
[HttpGet]
[Authorize(Roles = "admin")]
public async Task<IActionResult> Delete(string id)
{
RoleViewModel item = new RoleViewModel();
ApplicationRole role = await db.FindByIdAsync(id);
if (role != null)
{
item.RoleID = role.Id;
item.RoleName = role.Name;
item.Description = role.Description;
303
}
return View(item);
}
[HttpPost, ActionName("Delete")]
[Authorize(Roles = "admin")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(string id)
{
if (ModelState.IsValid)
{
ApplicationRole role = await db.FindByIdAsync(id);
var result = await db.DeleteAsync(role);
return RedirectToAction("Index");
}
return View();
}
}
}
Pada contoh di atas atribut [Authorize] tidak digunakan di atas nama class controller, tetapi
digunakan pada setiap method action. Kemudian dapat dilihat seluruh method action hanya
dapat diakses oleh role admin, kecuali method action Index yang dapat diakses oleh role
admin dan user. Aturan otorisasi tersebut membuat user dengan role user dapat mengakses
halaman daftar role tetapi tidak dapat melakukan penambahan, edit dah hapus data.
Dari penjelasan di atas maka pembaca dapat memiliki pengetahuan bagaimana membuat
aturan otorisasi sesuai dengan kebutuhan.
304
9
Penutup
Sebagai penutup, buku ini ditulis untuk para web developer yang ingin membangun aplikasi
web lintas platform dengan ASP.NET Core dengan database MS SQL Server dengan tool
development Visual Studio 2017.
Akhir kalimat, jika ada kritik dan saran dapat ditujukan langsung via email ke alamat
[email protected].
305