Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
oleh Stephen Walther
Pelajari cara memindahkan logika validasi Anda dari tindakan pengontrol dan ke lapisan layanan terpisah. Dalam tutorial ini, Stephen Walther menjelaskan bagaimana Anda dapat mempertahankan pemisahan kekhawatiran yang tajam dengan mengisolasi lapisan layanan Anda dari lapisan pengontrol Anda.
Tujuan dari tutorial ini adalah untuk menjelaskan salah satu metode melakukan validasi dalam aplikasi MVC ASP.NET. Dalam tutorial ini, Anda mempelajari cara memindahkan logika validasi anda dari pengontrol dan ke lapisan layanan terpisah.
Memisahkan Kekhawatiran
Saat Anda membuat aplikasi MVC ASP.NET, Anda tidak boleh menempatkan logika database Anda di dalam tindakan pengontrol Anda. Mencampur database dan logika pengontrol Anda membuat aplikasi Anda lebih sulit dipertahankan dari waktu ke waktu. Rekomendasinya adalah Anda menempatkan semua logika database Anda di lapisan repositori terpisah.
Misalnya, Listing 1 berisi repositori sederhana bernama ProductRepository. Repositori produk berisi semua kode akses data untuk aplikasi. Daftar ini juga mencakup antarmuka IProductRepository yang diterapkan repositori produk.
Daftar 1 - Models\ProductRepository.vb
Public Class ProductRepository
Implements IProductRepository
Private _entities As New ProductDBEntities()
Public Function ListProducts() As IEnumerable(Of Product) Implements IProductRepository.ListProducts
Return _entities.ProductSet.ToList()
End Function
Public Function CreateProduct(ByVal productToCreate As Product) As Boolean Implements IProductRepository.CreateProduct
Try
_entities.AddToProductSet(productToCreate)
_entities.SaveChanges()
Return True
Catch
Return False
End Try
End Function
End Class
Public Interface IProductRepository
Function CreateProduct(ByVal productToCreate As Product) As Boolean
Function ListProducts() As IEnumerable(Of Product)
End Interface
Pengontrol di Listing 2 menggunakan lapisan repositori dalam tindakan Index() dan Create(). Perhatikan bahwa pengontrol ini tidak berisi logika database apa pun. Membuat lapisan repositori memungkinkan Anda mempertahankan pemisahan kekhawatiran yang bersih. Pengontrol bertanggung jawab atas logika kontrol alur aplikasi dan repositori bertanggung jawab atas logika akses data.
Daftar 2 - Controllers\ProductController.vb
Public Class ProductController
Inherits Controller
Private _repository As IProductRepository
Public Sub New()
Me.New(New ProductRepository())
End Sub
Public Sub New(ByVal repository As IProductRepository)
_repository = repository
End Sub
Public Function Index() As ActionResult
Return View(_repository.ListProducts())
End Function
'
' GET: /Product/Create
Public Function Create() As ActionResult
Return View()
End Function
'
' POST: /Product/Create
<AcceptVerbs(HttpVerbs.Post)> _
Public Function Create(<Bind(Exclude:="Id")> ByVal productToCreate As Product) As ActionResult
_repository.CreateProduct(productToCreate)
Return RedirectToAction("Index")
End Function
End Class
Membuat Lapisan Layanan
Jadi, logika kontrol alur aplikasi termasuk dalam pengontrol dan logika akses data berada di repositori. Dalam hal ini, di mana Anda menempatkan logika validasi Anda? Salah satu opsinya adalah menempatkan logika validasi Anda di lapisan layanan.
Lapisan layanan adalah lapisan tambahan dalam aplikasi MVC ASP.NET yang menengahi komunikasi antara lapisan pengontrol dan repositori. Lapisan layanan berisi logika bisnis. Secara khusus, berisi logika validasi.
Misalnya, lapisan layanan produk di Listing 3 memiliki metode CreateProduct(). Metode CreateProduct() memanggil metode ValidateProduct() untuk memvalidasi produk baru sebelum meneruskan produk ke repositori produk.
Daftar 3 - Models\ProductService.vb
Public Class ProductService
Implements IProductService
Private _modelState As ModelStateDictionary
Private _repository As IProductRepository
Public Sub New(ByVal modelState As ModelStateDictionary, ByVal repository As IProductRepository)
_modelState = modelState
_repository = repository
End Sub
Protected Function ValidateProduct(ByVal productToValidate As Product) As Boolean
If productToValidate.Name.Trim().Length = 0 Then
_modelState.AddModelError("Name", "Name is required.")
End If
If productToValidate.Description.Trim().Length = 0 Then
_modelState.AddModelError("Description", "Description is required.")
End If
If productToValidate.UnitsInStock
Pengontrol Produk telah diperbarui di Daftar 4 untuk menggunakan lapisan layanan alih-alih lapisan repositori. Lapisan pengontrol berbicara dengan lapisan layanan. Lapisan layanan berbicara dengan lapisan repositori. Setiap lapisan memiliki tanggung jawab terpisah.
Daftar 4 - Controllers\ProductController.vb
Public Class ProductController
Inherits Controller
Private _service As IProductService
Public Sub New()
_service = New ProductService(Me.ModelState, New ProductRepository())
End Sub
Public Sub New(ByVal service As IProductService)
_service = service
End Sub
Public Function Index() As ActionResult
Return View(_service.ListProducts())
End Function
'
' GET: /Product/Create
Public Function Create() As ActionResult
Return View()
End Function
'
' POST: /Product/Create
<AcceptVerbs(HttpVerbs.Post)> _
Public Function Create(<Bind(Exclude := "Id")> ByVal productToCreate As Product) As ActionResult
If Not _service.CreateProduct(productToCreate) Then
Return View()
End If
Return RedirectToAction("Index")
End Function
End Class
Perhatikan bahwa layanan produk dibuat di konstruktor pengontrol produk. Ketika layanan produk dibuat, kamus status model diteruskan ke layanan. Layanan produk menggunakan status model untuk meneruskan pesan kesalahan validasi kembali ke pengontrol.
Memisahkan Lapisan Layanan
Kami telah gagal mengisolasi pengontrol dan lapisan layanan dalam satu hal. Pengontrol dan lapisan layanan berkomunikasi melalui status model. Dengan kata lain, lapisan layanan memiliki dependensi pada fitur tertentu dari kerangka kerja MVC ASP.NET.
Kami ingin mengisolasi lapisan layanan dari lapisan pengontrol kami sebanyak mungkin. Secara teori, kita harus dapat menggunakan lapisan layanan dengan semua jenis aplikasi dan tidak hanya aplikasi MVC ASP.NET. Misalnya, di masa depan, kita mungkin ingin membangun front-end WPF untuk aplikasi kita. Kita harus menemukan cara untuk menghapus dependensi pada status model MVC ASP.NET dari lapisan layanan kita.
Di Daftar 5, lapisan layanan telah diperbarui sehingga tidak lagi menggunakan status model. Sebaliknya, ia menggunakan kelas apa pun yang mengimplementasikan antarmuka IValidationDictionary.
Daftar 5 - Models\ProductService.vb (didecoupled)
Public Class ProductService
Implements IProductService
Private _validatonDictionary As IValidationDictionary
Private _repository As IProductRepository
Public Sub New(ByVal validationDictionary As IValidationDictionary, ByVal repository As IProductRepository)
_validatonDictionary = validationDictionary
_repository = repository
End Sub
Protected Function ValidateProduct(ByVal productToValidate As Product) As Boolean
If productToValidate.Name.Trim().Length = 0 Then
_validatonDictionary.AddError("Name", "Name is required.")
End If
If productToValidate.Description.Trim().Length = 0 Then
_validatonDictionary.AddError("Description", "Description is required.")
End If
If productToValidate.UnitsInStock
Antarmuka IValidationDictionary ditentukan dalam Daftar 6. Antarmuka sederhana ini memiliki satu metode dan satu properti.
Daftar 6 - Model\IValidationDictionary.cs
Public Interface IValidationDictionary
Sub AddError(ByVal key As String, ByVal errorMessage As String)
ReadOnly Property IsValid() As Boolean
End Interface
Kelas di Listing 7, bernama kelas ModelStateWrapper, mengimplementasikan antarmuka IValidationDictionary. Anda dapat membuat instans kelas ModelStateWrapper dengan meneruskan kamus status model ke konstruktor.
Daftar 7 - Models\ModelStateWrapper.vb
Public Class ModelStateWrapper
Implements IValidationDictionary
Private _modelState As ModelStateDictionary
Public Sub New(ByVal modelState As ModelStateDictionary)
_modelState = modelState
End Sub
#Region "IValidationDictionary Members"
Public Sub AddError(ByVal key As String, ByVal errorMessage As String) Implements IValidationDictionary.AddError
_modelState.AddModelError(key, errorMessage)
End Sub
Public ReadOnly Property IsValid() As Boolean Implements IValidationDictionary.IsValid
Get
Return _modelState.IsValid
End Get
End Property
#End Region
End Class
Terakhir, pengontrol yang diperbarui di Listing 8 menggunakan ModelStateWrapper saat membuat lapisan layanan di konstruktornya.
Daftar 8 - Controllers\ProductController.vb
Public Class ProductController
Inherits Controller
Private _service As IProductService
Public Sub New()
_service = New ProductService(New ModelStateWrapper(Me.ModelState), New ProductRepository())
End Sub
Public Sub New(ByVal service As IProductService)
_service = service
End Sub
Public Function Index() As ActionResult
Return View(_service.ListProducts())
End Function
'
' GET: /Product/Create
Public Function Create() As ActionResult
Return View()
End Function
'
' POST: /Product/Create
<AcceptVerbs(HttpVerbs.Post)> _
Public Function Create(<Bind(Exclude := "Id")> ByVal productToCreate As Product) As ActionResult
If Not _service.CreateProduct(productToCreate) Then
Return View()
End If
Return RedirectToAction("Index")
End Function
End Class
Menggunakan antarmuka IValidationDictionary dan kelas ModelStateWrapper memungkinkan kami untuk sepenuhnya mengisolasi lapisan layanan kami dari lapisan pengontrol kami. Lapisan layanan tidak lagi bergantung pada status model. Anda dapat meneruskan kelas apa pun yang mengimplementasikan antarmuka IValidationDictionary ke lapisan layanan. Misalnya, aplikasi WPF mungkin mengimplementasikan antarmuka IValidationDictionary dengan kelas koleksi sederhana.
Ringkasan
Tujuan dari tutorial ini adalah untuk membahas salah satu pendekatan untuk melakukan validasi dalam aplikasi MVC ASP.NET. Dalam tutorial ini, Anda belajar cara memindahkan semua logika validasi Anda dari pengontrol Anda dan ke lapisan layanan terpisah. Anda juga mempelajari cara mengisolasi lapisan layanan dari lapisan pengontrol dengan membuat kelas ModelStateWrapper.