Navigation

Wednesday, October 06, 2010

MVC in VB.NET Explained – An Introduction Written So You Can Understand It

If your new to MVC (Model, view, controller) and need a simple yet complete introduction to the topic this is a great article bu Dan Mabbut with About.com. (http://jpda.me/d06VCT).

MVC in VB.NET Explained, An Introduction Written So You Can Understand It.

In the beginning, there was Input-Process-Output. Everything since then is just more details.

That's literally true. The original computer, Eniac, input data about artillery, processed it, and spit out gunnery tables. But they soon learned that it could do so much more. They used it for computations necessary to create the first Hydrogen Bomb. (What would we do without war to underwrite invention?)

The way to understand MVC is to realize that it's just the latest detail on Input-Process-Output. Except that now, it's called Model-View-Controller. Model is Input, View is the Output, and Controller is Process. Sort of. Most authorities recommend that you put your "process" in "Model" and let "Controller" simply act as a switching function. But we're getting ahead of ourselves.

Although I'll be covering the same ground again, I've written several short articles about MVC:

Sorting Through the New Toys - MVC (April 28, 2010)

MVVM - A Fad or The Future? (May 27, 2010)

My new book, Pro ASP.NET 4 in VB 2010 also has a chapter about MVC where much more advanced concepts are explained, such as using MVC to create web pages based on an Entity Data Model generated from a database.

If you're a VB.NET programmer (and I assume that you are), then you now have your mind wrapped around something called the "event driven model". Just like MVC, programming this model depends on having a clear mental image of what the software does automatically and what you have to add. The key to doing MVC is to shift gears to a different mental image. So, let's consider event driven programming for just a second so we can contrast it with MVC.

When you write the standard "Hello World" program using event driven programming, you typically put a Button and a Label on a Form. When the Button is clicked, .NET creates an "event" called the "click event". Your task as a programmer is to anticipate that event and write the code that inserts a String into the Text property of a Label control.


Public Class Form1
Private Sub Button1_Click(
ByVal sender As System.Object,
ByVal e As System.EventArgs
) Handles Button1.Click
Label1.Text = "Hello World"
End Sub
End Class


The key here is that nothing works unless .NET generates that magical "event" that triggers the execution of your code. MVC is like that. You anticipate things that MVC does and then just insert your code into the right places to make the resulting system do what you want it to do. But you don't code for "events" anymore. (Well ... you can. But then you're working in parallel with MVC. MVC will allow you to insert event driven programming. But that works "on top of MVC" rather than being part of it. When learning MVC, the first thing to do is banish event driven programming from your mind.)



That's why the three circle diagram of MVC is used so much. (I've illustrated the first article linked above with the standard version.) Those three circles are the part that happens "automagically" and where you need to think about putting your code. Unfortunately, it's nowhere near as simple as Windows Forms, as we will see.



To see what the difference is, we're going to code a "Hello World" app using MVC from the ground up. That last part is important. Nearly every other example you will see on the web starts with a runable MVC shell app that is just modified. On the next page, we code an MVC app using the empty app template and add everything we need manually so you can understand what's there and why.



Step 1



You might already have VB.NET 2010 Express fired up and ready to go. Not so fast! Microsoft has chosen not to put any MVC templates in VB.NET Express. Right now, it's exclusively an ASP.NET web technology. So you have to have Visual Web Developer 2010 Express downloaded and fired up instead. (Fortunately, also free.) Or the full Visual Studio 2010 which can do anything.



Fundamentally, MVC is a "design pattern" and you could implement it by simply following the pattern and coding your own classes. I mention this because somebody will inevitably write in and tell me that "we don' need no steekin' templates". (Apologies to Treasure of the Sierra Madre.) Fundamentally, you could also code your own programs with nothing more than the vbc compiler and Notepad, too. We're talking about what's reasonable here.



So fire up Visual Web Developer 2010 Express and select New Project. Under Visual Basic and the Web subheading, you will see two likely templates:




  • ASP.NET MVC 2 Web Application


  • ASP.NET MVC 2 Empty Web Application



The first one is the one usually used. You can create a new project using that template and run it unchanged to get something like this:



--------

Click here to display the illustration.


--------



There's a lot going on there! And it's all included in the app. Here's the Solution Explorer view of the app:



--------

Click here to display the illustration.


--------



All of the code in those files fit together in an intricate interlocking scheme. Get one parameter out of place and it doesn't run. It's a lot easier to start with an app that already runs and then add, change, and delete to get what you want. But you don't learn as much, so we're going to start with an empty MVC app. When you do that, you get this result:



--------

Click here to display the illustration.


--------



Quite a difference. The error, by the way, is one of the most common ones that you will see as you learn to code using MVC. But all of the necessary pieces are still there. They just don't have the code to fit together anymore. That's what we're going to add. (But I'll still have to sprinkle "programmer pixie dust" in a few places before it will run.)



Step 2



Let's start at the data end: Models. In a realistic business app, the Models folder contains the code to interface with a database or some other source of data. Much of the actual processing takes place in the Models because an underlying philosophy of MVC is complete isolation of function. MVC gurus call this the "Single Responsibility Principal". The other parts of MVC, Controllers and Views, should not know or care where the data comes from. In a real world app, globalization, validation, authorization ... anything necessary to get the data ... will be found here.



In our little "Hello World" app, we only have one piece of data: the string "Hello World!" To add that to the Models folder, right-click the Models folder and add a class named HelloDataModel.vb. Here's the code that goes in this file:




Namespace MVCHelloWorld.Models
Public Class HelloDataModel
' The data: A Hello World string
Public Property theHello As String = "Hello World!"
End Class
End Namespace


It looks pretty simple because it's just one class containing one property. But it's not quite that simple because MVC ties together with names and all the names have to be present and match before it works. So, for example, you will find that you use the Namespace keyword a lot. In Windows Forms, you can pretty much ignore it most of the time. In a realistic app, much of the actual work is done by attributes that are used to decorate the classes. For example, in the boilerplate AccountModel file for the non-empty MVC app, the Password property is decorated with four attributes:




<Required()> _
<ValidatePasswordLength()> _
<DataType(DataType.Password)> _
<DisplayName("Password")> _
Public Property Password() As String
...


Often, these attributes have to be supported by other classes that you code. And so on and so on ...



On the next page, we code the heart of MVC, the controller.



Next, let's look at the controller. You can add a file named HelloController.vb to the Controller's folder by right-clicking the Controllers folder and selecting Add. Once you get the boilerplate in place, modify it as shown here:




Namespace MVCHelloWorld.Models
Public Class HelloController
Inherits System.Web.Mvc.Controller
Public Function Greet() As ActionResult
Dim theHelloGreeting As New HelloDataModel
ViewData("Message") =
theHelloGreeting.theHello
Return View()
End Function
End Class
End Namespace


The first thing to notice is that we use the same Namespace that we used in the Models. This won't always be the case. In MVC, things are organized into logical categories using namespaces. You could have several in your program.



The second thing to notice is that this class inherits System.Web.Mvc.Controller. That's where the class gets most of its core functionality. Controllers do things that you won't expect coming from a Windows Forms background because those functions are built into the parent.



And the third thing to notice is that the end product of this class is an ActionResult named Greet. The ActionResult types in the non-empty MVC app are named Index and About. The standard CRUD (Create-Read-Update-Delete) functions are all ActionResults in a real world app. List is an ActionResult. The controller classes usually don't do anything. They just decide what gets done next as a result of what they're passed. This one decides that displaying a greeting should be done next. But it doesn't actually display it. That's done by a view.



Once you have coded the controller, you can also create a view by right-clicking the code in the controller.



--------

Click here to display the illustration.


--------



The Microsoft team has done some good work supporting MVC in their development tools. The linkage between controllers and views is one of the more intricate ways that MVC ties together and they've made it somewhat easier. But the dialog window that is displayed next will still raise a lot of questions if you haven't seen it before.



--------

Click here to display the illustration.


--------



To make things easier, I copied a Master Page from another project and then modified it to remove all the things I wouldn't use. A master page isn't required, but it's a good idea. Here's the page I used:




<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title><asp:ContentPlaceHolder
ID="TitleContent" runat="server" /></title>
<link href="../../Content/Site.css"
rel="stylesheet" type="text/css" />
</head>

<body>
<div class="page">
<div id="main">
<asp:ContentPlaceHolder
ID="MainContent" runat="server" />
</div>
</div>
</body>
</html>


You can see that things are still linking together by name. For example, you'll see the ID MainContent again in the view, which we consider next.



If you used the dialog to create the view, you will notice that both a Hello folder and a Greet.aspx file in the folder have been added for you. The .aspx files in Views aren't normal .aspx files. For one thing, there is no corresponding .vb code behind file. You don't do any processing in Views, so there is no place to put code. I modified the Greet.aspx file to contain this code:




<%@ Page Title="" Language="VB"
MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="Content1"
ContentPlaceHolderID="MainContent" runat="server">
<h1><%=ViewData("Message") %></h1>
</asp:Content>


The ViewData object is just a keyed dictionary. In this case, Message is the key. It was created in the controller. A lot of MVC purists don't like this technique because (they say) the controller shouldn't be doing any processing. Because MVC is still under active development, and there are lots of other flavors other than the Microsoft brand, you'll see this sort of debate if you start reading about it.



You might think that you're finished now. You might be wrong. There's still more plumbing to put in place and on the next page, we complete the app.



The final code we need is in a file that has been there in other ASP.NET applications, but is used a lot more in MVC: Global.asax. Actually, the code is in the partial code-behind class, Global.asax.vb. (There are also sections added to Web.config to make routing work, but you normally don't have to do anything with them, so you can delay figuring out what they do.) The primary thing that is added to Global.asax is routing. This is a critical part of MVC and defines how incoming browser requests are mapped to particular MVC controller actions. Routing instructions are created in a table when the application is started. The Application_Start() subroutine executes another sub:




RegisterRoutes(RouteTable.Routes)


RegisterRoutes actually builds the table with a series of instructions that are helpfully documented in comments in Global.asax along with the default that is used in the non-empty MVC app:




' MapRoute takes the following parameters, in order:
' (1) Route name
' (2) URL with parameters
' (3) Parameter defaults
routes.MapRoute( _
"Default", _
"{controller}/{action}/{id}", _
New With {.controller = "Home",
.action = "Index",
.id = UrlParameter.Optional} _
)


This is why MVC apps don't use normal looking URL's. A typical MVC URL might look like this:




http://myDomain.com/Home/Index/3


The routing table will send this to the Home controller; the Index action; and pass the parameter 3, which is often an index into a database.



Routing instructions in the table are used in sequence. If an earlier table entry satisfies the incoming browser request, then later entries aren't used. You can code these table entries so that multiple requests will "match" table entries for enormous flexibility (and not just a little complexity too). For this reason, you will normally place your routing instructions above the generated entries that are already in Global.asax. In my case, I didn't use a Home controller or an Index action, so I recoded the default this way:




routes.MapRoute(
"Default", "{controller}/{action}",
New With {
.controller = "Hello",
.action = "Greet"
})

So for my app, the "Default" url will call Hello.Greet() with this result:

--------

Click here to display the illustration.


--------



Ta-Da!!!



If you think this is a lot of trouble to display "Hello World!" you're right. The main features of MVC do not include simplicity; they include long term application maintainability, flexible design, and efficient execution. (For example, there are no No ViewState and PostBack events clog up the network.) But it does take some getting used to!

1 comment:

VB.Net Migration said...

Very well article information about vb.net.