A Very Simple .net Model View Controller
secretGeek .:dot Nuts about dot Net:.
home .: about .: sign up .: sitemap .: secretGeek RSS

A Very Simple .net Model View Controller

MVC. Model View Controller. Ahhh. One of those pattern things that your java kids are fond of. And now getting a lot of love from the RoR crowd.

From what I can tell so far, one of the main historical uses of MVC is to give dull people something to argue about.

"No no -- that's not pure MVC! If you go back to page 97 of GoF..."

And yet... I'm intrigued. The promise is nice.

I haven't found any simple examples using MVC for a .net application. So I'll give it a go. And it will be bad and you will tell me how to improve it ;-)

It's the view/controller bit that I'm a little mixed up with.

First, here's my architecture (notice the small 'a' in architecture... )

View a windows form in this example /\ || \/ Controller class that co-ordinates between Model and View /\ || \/ Model Your business object, an 'AppUser' in this example

Have I gone off the track yet?

Principles

  • No 'business rules' in the view.
  • The view in fact knows nothing about the model.
  • The 'model' knows nothing about the view.
  • The less code in the view, the better.
  • The controller doesn't care whether the view is a web form or a windows form.

Before I show you this approach -- let me point out that i'm not advocating it -- i'm just throwing it out there, to see what problems you've got with it.

Okay so inside our Login form, we have this variable:

    Private WithEvents m_LoginController As New LoginController

So, the Login Form has a member variable of type LoginController and as it happens we've declared that we're interested in events that this object might raise (i.e. 'WithEvents') (we'll see the reasons for this soon enough).

(Question: Should we have one controller for each form, like i'm doing here? or one controller for the whole app? If we have one controller for each form, then our view platform is dictacting the structure of our control -- since the type of viewing platform will determine the optimal complexity of a single form. Never mind... Let's make it one controller per form and see if anyone complains.)

Okay when the Login button is clicked we tell the controller.

 

    Private Sub btnLogin_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLogin.Click

        'The view doesn't know what a user is!

        'The view doesn't know how passwords are validated...

        'It just **looks pretty** and **does what it's told!**

        m_LoginController.Login(txtUserName.Text, txtPassword.Text)

    End Sub

The login controller is notified.

And that's all the code we have in any event handlers from our controls. Seem easy.

Now what happens inside this Login Controller?

Okay -- so this login controller is going to have to talk to "the model". I figure the model contains my business objects: in this case there's probably a "User" class of some sort. Let's say that there's a class called AppUser and it's in a namespace called Model.

    Public Class LoginController

 

        'The controller knows what's happening on the view... but doesn't know the

        'names of the controls... or anything about the way the thing looks.

        Public Sub Login(ByVal Username As String, ByVal Password As String)

            'The controller knows a bit about the back-end.. the 'model'

            Dim currentUser As New Model.AppUser

            Dim result As Boolean = currentUser.Login(Username, Password)

            '!! Somehow notify the View!!

        End Sub

 

    End Class

The Login controller also has to talk back to the view somehow: and for this rambling demo I've chosen to use "events". We can notify the view that something has happened...

    Public Class LoginController

 

        Public Event LoginFailure(ByVal Message As String)

        Public Event LoginSuccess(ByVal Name As String)

 

        Public Sub Login(ByVal Username As String, ByVal Password As String)

            Dim currentUser As New Model.AppUser

            Dim result As Boolean = currentUser.Login(Username, Password)

            If Not result Then

                '!! Use events to communicate with the view.

                RaiseEvent LoginFailure("Login failed")

            Else

                RaiseEvent LoginSuccess(currentUser.Name)

            End If

        End Sub

 

    End Class

Now back in the windows form, we have handlers for the events raised by the Controller.

    Private Sub ShowLoginFailure(ByVal Message As String) _

            Handles m_LoginController.LoginFailure

        'Clear the password field.       

        txtPassword.Text = ""

        'Display the failure message

        lblMessage.Text = Message

        'Set focus to the username control

        txtUserName.Focus()

    End Sub

 

    Private Sub ShowLoginSuccess(ByVal Name As String) _

            Handles m_LoginController.LoginSuccess

        'Notice that the view has decided not to do anything with the 'Name' parameter.

        'The view gets to make all the visual decisions

        Me.DialogResult = DialogResult.OK

        Me.Close()

    End Sub

Now I've got a bunch of problems with the above implementation. It seems over-engineered, adds extra code for little benefit.

Am i doing it wrong? Thinking about it wrong? Or both?

What do you see?





'Matt Hamilton' on Fri, 27 Oct 2006 05:46:39 GMT, sez:

The irony is that in real life it's *models* who look pretty and do what they're told.



'owen' on Fri, 27 Oct 2006 06:20:37 GMT, sez:

this approach seems to be to be a very simmilar argument to the <a href="http://c2.com/cgi/wiki?TheHumbleDialogBox">humble dialogue</a> arguement..

we find the whole aproach of having a very thin presentation layer. and then a controller layer on top of the business layer really really valuable...

a) Testable... ASP.net pages are a b**ch to test, slow as a dog and less than meaningful results so we try and keep all logic away from the ASP.net pages themselved

b) Vocabulary.. by seperating the business logic from the display we can better describe our business object code in a more meanigful sintax.

that is all. so i personally am a big fan.



'Simon' on Fri, 27 Oct 2006 06:38:58 GMT, sez:

It seems like extra code because it basically is. Visual Studio auto generates a load of stuff in a certain way. If it auto generated MVC code, then it wouldn't seem like it. Rails auto generates a load of this stuff, so it doesn't seem like it.



'Zooba' on Fri, 27 Oct 2006 07:04:54 GMT, sez:

Generally, one controller class per process. Alternatively (IMHO, pure OO-ists don't like this much), one controller class per type of process. So your LoginController may be able to authenticate the user, as well as change passwords and allow administrative control of password expiry, etc.

I'm not real happy with how the OO people have hijacked this pattern as their own, since it quite often works as well if not better with different paradigms (for example, OO GUI/view, procedural controller, RDBMS data/model).



'Laurent' on Fri, 27 Oct 2006 07:45:39 GMT, sez:

I would say that ASP.NET internal plumbing is partly MVC already. Unfortunately, you have to forget about plug the same controllers in WinForms applications...

An .ASPX file can fit the "View" rôle, as "Controller" is handled the System.UI.Web.Page object.

You may want to design your own "Controller" by creating a class that inherits from System.UI.Web.Page: that's what .cs class files in the @CodeFile attribute are done for.

According to "Model", I prefer to write custom business object instead of playing with datasets / dataadapter.

That's the point of view of a developper which wants to keep it very simple and do not want to fall in the "frameworkitis" trap once again :)



'Omer van Kloeten' on Fri, 27 Oct 2006 09:00:33 GMT, sez:

I find the Model View Presenter pattern better for the sake of testing.
You should really consider using it as it's not far from classic MVC.



'Ryan Patterson' on Fri, 27 Oct 2006 10:56:06 GMT, sez:

"Unfortunately, you have to forget about plug the same controllers in WinForms applications..."

You have lost the point of the Controller. It is a presentation-neutral object! Don't think only in terms of human inerface, either. Look at what owen says: a different View may be useful for testing.



'RobC' on Fri, 27 Oct 2006 12:14:49 GMT, sez:

Often it is the simple cases that make the pattern look pointless.

Try another where you have two views each using the same controller. One view is a graph the other is a grid. Then it begins to make sense. Both views need to do the same thing.

Also consider complex views where the available input depends on the state of the model. Then the controller can wrap up the logic as to whether a particular input should be available or not. The view decides whether this means that it is visible or disabled or purple whatever. In this case testing becomes important and it is much easier to write an NUnit test for a controller than a form. (Yes I do know it can be done.)



'Steve Betts' on Fri, 27 Oct 2006 13:12:17 GMT, sez:

I have an issue with your basic layout of the MVc classes. The Model holds the data, the View displays the data to the user, and the controller makes changes to the data.

The view knows all about the model. It subscribes to change notifications from the model. The view updates the display when the model changes.

The view knows about the controller. The view receives input from the user and tells the controller. For example, the view gets a click on the Login Button, the view tells the controller that the user clicked and where. For example, controller.click(Btn).

The controller translates the user action into model changes. That is, it will take the click to mean "Login" and get the user/password from the model, do the authentication, and then update the model with the result.

When the model is updated, it will notify it's listeners (the view in this case). The view will update the display to match the changes in the model. Error messages or sucess notification or whatnot.

This is not the easiest example, because the process doesn't cycle.

Perhaps it would be easier with the entry of the username into the proper field.

Assume that the model, view, and controller are all set up already. The view is displayed, and fills the username field with the user name from the model. I'd assume that the model user name would be blank to start.

The user enters a username. The view notifies the controller that the user typed into the username field. The controller will then update the model. The model would notify the view that the username field changed. The view would update the username field with the new value.

Again, in this simple case, the view would know that the user has made the change and not make the change again, to avoid the infinite loop. A standard pattern to reduce this looping is pass the originator of the change along with the notification, so that the originator knows not to update again.

In fancier setups, there would likely be several different views on the model, to present the data in different ways, and that's when this pattern really starts to shine.

So, is this clear?



'Haacked' on Fri, 27 Oct 2006 14:39:08 GMT, sez:

I'm with Omer, I think MVP is easier to understand as well.

Also, I think you really do have to consider your platform, Windows or Web.

I call YAGNI on this idea that you're really going to take your same controller/presenter that you developed for a Web Page and drop it into a WinForm.

How many times in your career have you done that verse not done that? ;) This is why I let my Presenter code have some ties to the underlying View platform (http://haacked.com/archive/2006/08/09/TyingMVPToTheASP.NETEventModel.aspx)

Because rather than traffic in theory, I like to get things done.



'Dominic Cronin' on Fri, 27 Oct 2006 18:59:14 GMT, sez:

Except that you can't go to page 97 (or whatever) of GoF for this, because it's not one of the patterns they describe. They do give it an honourable mention in their introduction, however.

Not to be pedantic or anything; it's just that I find it funny that the biggest, bitchingest, grandaddy-of-em-all Design Pattern didn't make the book, even though they knew of it.



'aviNash' on Sat, 28 Oct 2006 03:13:49 GMT, sez:

I've done a variant of what you are saying - just a little different though.

The View creates an instance of the controller (as you describe) but passes its reference into the controller. The control stores the reference to the view and hooks into the Views events. Additionally the Controller also creates instances of the Model and works with it. The View is really thin and has almost no code in it. Of course other than what the IDE writes out.

In my case I only work with WinForms and so this works allright without over-engineering for features we'll probably never need. But if we really did need the ability work with WinForms and WebForms transparently, I suppose introducing a template method pattern for the Controller and also a factory to produce the right controller Win/Web would do the trick. I'm thinking the template method pattern because all that I see is different b/w the win and web controller is the underlying view type and also the way events work.

Not sure if this is a good way - but thats the way I've done it and works fairly well for me.

Thanks.



'Pitarou' on Sat, 28 Oct 2006 15:16:46 GMT, sez:

> Now I've got a bunch of problems with the
> above implementation. It seems
> over-engineered, adds extra code for little
> benefit.

Congratulations on noticing that it sucks! This puts you in the top 10% of Design Pattern weenies. :-)

A Design Pattern is a tried-and-tested solution to a commonly arising problem. If the problem doesn't exist, the Design Pattern just makes your code suck.

Going back to your example, MVC addresses the coherency problems arising in a system with multiple types of user and interface. You are using MVC in a system with one type of user and one interface. Ergo, it sucks.



'mike' on Tue, 31 Oct 2006 13:51:07 GMT, sez:

Um, Leon, this discussion is longer than 3 minutes, so it exceeds my attention span. Can you, like, take care of that? Thx.

But, sigh, while I'm here, how does MVC map to the page-BL-DAL-provider model in ASP.NET? (In particular, where does the provider fit in here?)



'Vitamin C' on Thu, 16 Nov 2006 02:57:55 GMT, sez:

@Pitarou,

MVP grants you benefits such as testability and mockability. Something that is difficult if you tie up the code in asp.net codebehind.



'sallyann herbert' on Mon, 09 Apr 2007 13:00:30 GMT, sez:

are uyou looking for any models tb



'SuperGeek' on Sun, 23 Dec 2007 13:01:41 GMT, sez:

Well well I never heard so much triffle about something so simple. Looks like Patterns were invented to make programming a "science" rather than an art!



'Eicks' on Fri, 31 Aug 2012 22:11:35 GMT, sez:

Very easy to understand. Cheers for that.




name


website (optional)


enter the word:
 

comment (HTML not allowed)


All viewpoints welcome. Incivility is not tolerated, such comments are deleted.

 

I'm the co-author of TimeSnapper, a life analysis system that stores and plays-back your computer use. It makes timesheet recording a breeze, helps you recover lost work and shows you how to sharpen your act.

 

NimbleText - FREE text manipulation and data extraction

NimbleText is a Powerful FREE Tool

I wrote this, and use it every day for:

  • extracting data from text
  • manipulating text
  • generating code

It makes you look awesome. You should use NimbleText, you handsome devil!

 

Articles

The Canine Pyramid The Canine Pyramid
Humans: A Tragedy. Humans: A Tragedy.
ACK! ACK!
OfficeQuest... Gamification for the Office Suite OfficeQuest... Gamification for the Office Suite
New product launch: NimbleSET New product launch: NimbleSET
Programming The Robot from Diary of a Wimpy Kid Programming The Robot from Diary of a Wimpy Kid
Happy new year 2014 Happy new year 2014
Downtime as a service Downtime as a service
The Shape of Your Irrationality The Shape of Your Irrationality
This is why I don't go to nice restaurants any more. This is why I don't go to nice restaurants any more.
A flowchart of what programmers do at work all day A flowchart of what programmers do at work all day
The Telepresent Man. The Telepresent Man.
Interview with an Ex-Microsoftie. Interview with an Ex-Microsoftie.
CRUMBS! Commandline navigation tool for Powershell CRUMBS! Commandline navigation tool for Powershell
Little tool for making Amazon affiliate links Little tool for making Amazon affiliate links
Extracting a Trello board as markdown Extracting a Trello board as markdown
hgs: Manage Lots of Mercurial Projects Simultaneously hgs: Manage Lots of Mercurial Projects Simultaneously
You Must Get It! You Must Get It!
AddDays: A Very Simple Date Calculator AddDays: A Very Simple Date Calculator
Google caught in a lie. Google caught in a lie.
NimbleText 2.0: More Than Twice The Price! NimbleText 2.0: More Than Twice The Price!
A Computer Simulation of Creative Work, or 'How To Get Nothing Done' A Computer Simulation of Creative Work, or 'How To Get Nothing Done'
NimbleText 1.9 -- BoomTown! NimbleText 1.9 -- BoomTown!
Line Endings. Line Endings.
**This** is how you pivot **This** is how you pivot
Art of the command-line helper Art of the command-line helper
Go and read a book. Go and read a book.
Slurp up mega-traffic by writing scalable, timeless search-bait Slurp up mega-traffic by writing scalable, timeless search-bait
Do *NOT* try this Hacking Script at home Do *NOT* try this Hacking Script at home
The 'Should I automate it?' Calculator The 'Should I automate it?' Calculator

Archives Complete secretGeek Archives

TimeSnapper -- Automated Screenshot Journal TimeSnapper: automatic screenshot journal

25 steps for building a Micro-ISV 25 steps for building a Micro-ISV
3 minute guides -- babysteps in new technologies: powershell, JSON, watir, F# 3 Minute Guide Series
Universal Troubleshooting checklist Universal Troubleshooting Checklist
Top 10 SecretGeek articles Top 10 SecretGeek articles
ShinyPower (help with Powershell) ShinyPower
Now at CodePlex

Realtime CSS Editor, in a browser RealTime Online CSS Editor
Gradient Maker -- a tool for making background images that blend from one colour to another. Forget photoshop, this is the bomb. Gradient Maker



[powered by Google] 

How to be depressed How to be depressed
You are not inadequate.



Recommended Reading


the little schemer


The Best Software Writing I
The Business Of Software (Eric Sink)

Recommended blogs

Jeff Atwood
Joseph Cooney
Phil Haack
Scott Hanselman
Julia Lerman
Rhys Parry
Joel Pobar
OJ Reeves
Eric Sink

InfoText - amazing search for SharePoint
LogEnvy - event logs made sexy
Computer, Unlocked. A rapid computer customization resource
Aussie Bushwalking
BrisParks :: best parks for kids in brisbane
PhysioTec, Brisbane Specialist Physiotherapy & Pilates
 
home .: about .: sign up .: sitemap .: secretGeek RSS .: © Leon Bambrick 2006 .: privacy

home .: about .: sign up .: sitemap .: RSS .: © Leon Bambrick 2006 .: privacy