Bagikan melalui


Memvalidasi dengan Lapisan Layanan (VB)

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.