Model-View-Presenter (MVP) in VB ASP.Net

29 Oct

Introduction

After spending quite a bit of time being sucked into the whole Code Behind mess of ASP.Net, I am finally getting some use out of the MVP pattern. There will have been plenty written about what it is, that it is a UI pattern and its many benefits, suffice to say that is what we should be aiming for when designing user, business and data layer components behind a user interface, be it ASP.Net, WinForms, Mobile, etc. Why? Because we are trying to achieve some important tenets of good design that being loose coupling with high cohesion. Cohesion is about robust, reliable, understandable and reusable designs/applications whilst loose coupling is about communicating through a stable interface. Another huge benefit to using this pattern for interface programming is that it allows you write tests that mock the various interface implementations to allow isolated unit testing.

Side Note:

I do have some reservations for using this pattern, particularly as I do a fair bit of work with datagridview controls(WinForms) or DataGrid (ASP.Net) as the intention of the pattern is to use the “View” to represent the data items relating to the user interface which is far more complicated when dealing with collections of datarows. Also, the handling of events and different code paths through the UI code behind make this pattern more cumbersome to implement and use. But more on that in a part 2 posting.

The alternative to MVP seen in many solutions is to use the code behind to assemble serialisable domain classes or xml documents and pass these between UI and user process code ensuring that the user process layer, business and data layer make no reference whatsoever to the original UI presentation data items such as text and combo boxes. This is often also achieved with the use of web services between the layers.

The View

The View shows a representation of the model and is usually distinguished by a stable interface e.g:-

Public Interface IView
   Property FullName() As String
   Property DateOfBirth() As String
   Property ErrorMessage() As String
End Interface

The Model

The Model is responsible for execution of business rules and storage of the data and again is usually distinguished by a stable interface e.g:-

Public Interface IModel
   Function StoreDetails(ByVal dets As IView) As String
   Function GetDetailsByID(ByVal idx As Integer) As ArrayList
   Function GetDetailsByName(ByVal name As String) As ArrayList
End Interface

The model will be supported by the associated concrete implementation. This example is of course highly contrived but the pattern underneath is the key principle here:-

Public Class Model
    Implements IModel

Public Function GetDetailsByID(ByVal idx As Integer) As System.Collections.ArrayList
  Implements Model.GetDetailsByID
       'Code to retrieve form details
       Dim res As ArrayList = New ArrayList(New String() {"simon", "Peter", "Jane"})
       Return res
  End Function

Public Function GetDetailsByName(ByVal name As String) As System.Collections.ArrayList
    Implements IModel.GetDetailsByName
      'Code to retrieve form details
      Dim res As ArrayList = New ArrayList(New String() {"Peter", "Jane"})
      Return res
  End Function

Public Function StoreDetails(ByVal dets As IView) As String Implements IModel.StoreDetails
      'Code to store form details
      '...
      Return String.Format("Stored details for {0} : {1}", dets.FullName, _
                                                      Format(CDate(dets.DateOfBirth), "yyyy/MM/dd"))
  End Function
End Class

The Presenter

The Presenters job is to present the view to the model and in so doing communcate between these layers:-

Public Class Presenter
   Dim thisView As IView
   Dim busLayer As IModel = New Model

   Public Sub New(ByVal view As IView)
      If view Is Nothing Then
         Throw New ArgumentException("view cannot be nothing")
      Else
         thisView = view
      End If
   End Sub

Function ValidateDOB() As Boolean
      Return IsDate(thisView.DateOfBirth)
End Function

Function StoreDetails() As String
      Return busLayer.StoreDetails(thisView)
   End Function
End Class

The Code behind file

Finally, the code behind ASP.Net page (could easily be some other UI client type) must implement the view’s interface and store the specifics of the UI controls values in the view and invoke the presenter to mediate between the UI and the model layers using the View data:-

Partial Class _Default
   Inherits System.Web.UI.Page
   Implements IView

   Dim thisView As IView  

Public Property DateOfBirth() As String Implements IView.DateOfBirth
      Get
         Return Me.TxtDOB.Text
      End Get
      Set(ByVal value As String)
         Me.TxtDOB.Text = value
      End Set
   End Property

Public Property FullName() As String Implements IView.FullName
      Get
         Return Me.TxtFullName.Text
      End Get
      Set(ByVal value As String)
         Me.TxtFullName.Text = value
      End Set
   End Property
Public Property ErrorMessage() As String Implements IView.ErrorMessage
      Get
         Return Me.LblResult.Text
      End Get
      Set(ByVal value As String)
         Me.LblResult.Text = value
      End Set
   End Property

Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles BtnSubmit.Click
      Try
         Dim pres As Presenter = New Presenter(Me)
         Me.LblResult.Text = pres.StoreDetails()
      Catch ex As Exception
         Me.LblResult.Text = ex.Message
      End Try
   End Sub
End Class

Conclusion

So, a fairly simple example to start with. The complications to this pattern will arise from the use of gridviews and data containers with many rows as well as how to handle page transitions, session data and page workflow and it may be that other patterns are required to fully implement a neat solution.

In the seond part to this article I will attempt to address these issues.

Tags: , , , ,

3 Responses to “Model-View-Presenter (MVP) in VB ASP.Net”

  1. tim September 11, 2009 at 3:34 am #

    Where is the 2nd part of this article? Please let me know.

  2. Tran Minh Ha August 23, 2011 at 1:41 pm #

    The replace the context “Dim busLayer As IModel = New Model” by the context “Dim busLayer As New Model”

    • nomisit January 3, 2012 at 10:10 pm #

      Hi Tran,

      By using the variable “busLayer” as an interface type before instantiating the concrete class “Model”, I am merely showing that you could put every type of object into the “busLayer” variable that implements the interface “IModel”. Those objects do not have to share the same base class. For me this is what interfaces are about: handling different objects as if they were of the same type whilst not having to share the same base class.

      I guess it’s a question of your coding style and the fact that this example is somewhat contrived and lacks real world complexity, where such definitions would perhaps be more useful in unit testing/mocking.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.