Saturday, February 9, 2013

Controller


ASP.Net MVC Controller is the fifth post in a series of tutorials which introduces the basics of ASP.Net MVC programming.

You can download the example code for the Model, View and Controller posts here. Visual Studio 2012 is required. If you don't have a copy, you can download a free copy of Visual Studio 2012 for Web.

Previous Posts:
MVC Introduction
HTML Forms
Model
View

Controllers

Controllers are responsible for responding to requests made on an ASP.Net MVC website. On a non-MVC site, a request is made explicitly for a file e.g. http://www.blogger.com/index.html. In MVC the request is made to the controller. Requests are either GET or POST which I reviewed in the second post on MVC.
This can be a difficult concept at first as there is a tendency to think that the View e.g. Edit.cshtml file is what is being requested but in actual fact the Controller is the first port of call and you can decide what view you want to display in the Controller.

Like Models and Views, there is a convention for how Controllers are named and where they are stored. Controllers are stored in the Controllers folder and are generally named to match the object with 'Controller' appended to the end e.g. PeopleController. Notice I am using People and not Person. Plural names are used for Controllers e.g. Cars, Products, People, etc.

If you look in the Controllers folders, there should be two controllers there which are generated from a template. AccountController manages registration and logins and the HomeController is a generic controller that manages the Views in the Home folder which current is the Index and About view.


We will add a Controller for our Person.

To add a Controller, right click on the Controllers folder, select add and then Controller. Name the controller PeopleController.
Select Controller with empty read/write actions as the template.


Like Add View, ASP.Net MVC will scaffold basic code to get started with a Controller.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Acme.Intranet.Models;

namespace Acme.Intranet.Controllers
{
    public class PeopleController : Controller
    {
        //
        // GET: /People/

        public ActionResult Index()
        {
            return View();
        }

        //
        // GET: /People/Details/5

        public ActionResult Details(int id)
        {
            return View();
        }

        //
        // GET: /People/Create

        public ActionResult Create()
        {
            return View();
        } 

        //
        // POST: /People/Create

        [HttpPost]
        public ActionResult Create(Person person)
        {
            try
            {
                // TODO: Add insert logic here

                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }
        
        //
        // GET: /People/Edit/5

        public ActionResult Edit(int id)
        {
            return View();
        }

        //
        // POST: /People/Edit/5

        [HttpPost]
        public ActionResult Edit(int id, Person person)
        {
            try
            {
                // TODO: Add update logic here

                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }

        //
        // GET: /People/Delete/5

        public ActionResult Delete(int id)
        {
            return View();
        }

        //
        // POST: /People/Delete/5

        [HttpPost]
        public ActionResult Delete(int id, Person person)
        {
            try
            {
                // TODO: Add delete logic here

                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }
    }
}


The Controller will contain a number of actions which return ActionResults which are a generic class that are returned by controllers. There are more complex return types but they are generally inherited from ActionResult.

The View created in the previous post provides a form for a person to be created. I will concentrate on the Actions for Create only. Notice there are two Create functions. The first is a GET action and he second is a POST action. You can restrict the action to POST by placing [HttpPost] attribute above the action.

As noted in the previous post on HTML forms, GET is primarily used to retrieve data while POST is used to submit data. MVC is a commonly referred to as a RESTful architecture. The client requests resources from the server e.g. a web page, the server then rests and does nothing until another GET or POST action is requested. In between requests, the server goes off and serves other requests. This is extremely efficient and is the significant reason for the success of the internet. Windows applications based on a client server model would run out of memory very quickly if it had to deal with the amount of requests that some web sites have to deal with. This is because windows applications retain a relationship with the client requesting information and must allocate memory for each client.

First, lets look at the GET action. The function will return a View when http://acme/people/create is requested. Hows does MVC know where to find the Create function. Again MVC relies on convention. MVC has a routing mechanism which will be expanded upon in a separate post. If you don't change anything, the following routing applies:

domain/controller/action e.g. http://acme/people/create, http://localhost:1388/car/delete

So MVC looks carefully at the URL and knows that everything after http:// and before the first / is the domain, the next part s the Controller and the last part is the Action. Note, the Controller part is omitted from the URL so PeopleController becomes people. The URL is not case sensitive so people is the same as People.


        //
        // GET: /People/Create

        public ActionResult Create()
        {
            return View();
        } 


The GET action returns a View. For now, think of a view as an empty model e.g. Person. If you want to populate the initial web form with some data, you can initialise a new person object and return it. If we had included a DateCreated field in person:


        //
        // GET: /People/Create

        public ActionResult Create()
        {

            Person person = new Person();
            person.DateCreated = DateTime.Now;

            Viewbag.Title="New Person";

            return View(person);
        } 


         

Now every person is initialised with the DateCreated set to the current date and time.

That is all that is required to show the person on the View. We now need a function to accept the POST action. The following function does nothing really but return the user to a view named Index. Note, the scaffolding that created the controller may have included a FormsCollection object instead of the Person object. Replace public ActionResult Create(FormCollection collection) with public ActionResult Create(Person person) as below:


        //
        // POST: /People/Create

        [HttpPost]
        public ActionResult Create(Person person)
        {
            try
            {
                // TODO: Add insert logic here

                return RedirectToAction("Index");
            }
            catch
            {
                return View();
            }
        }

Also ensure that the namespace which Person belongs to is referenced at the top e.g. using Acme.Intranet.Models;

The POST action returns a RedirectToAction which causes the browser to issue a GET request. In the example above, after the code is completed, the browser will go to the Index view for the Person e.g. http://acme/people/index. You an change this to return RedirectToAction("Edit"); and it will return to the current Edit view.

Important: If the [HttpPost] attribute is not placed above the action, the action method will be assumed to be GET.

Initially MVC may seem like a lot of overhead as there are a lot of new concepts to learn if you have come from ASP.Net forms or scripting languages. The good news is that MVC follows rules and once you become familiar with these rules, it makes life so much simpler.

You can download the example code for the Model, View and Controller posts here.

If you haven't used Visual Studio before, run the Visual Studio application, from the File menu select Oen Project, browse to the location where you extracted the files and select MvcTutorial1.sln. After the application loads, click the F5 button or select Start Debugging from the Debugging menu. The ASP.Net MVC application will open in your default browser. The initial URL will be a series of numbers like http://localhost:49529/. Type People/Create after the URL address e.g. http://localhost:49529/People/Create.
Hopefully you will see a web page similar to below:


Note: The form will not save data yet as we have not added a repository.

Concepts covered

  1. Controllers
  2. Actions
  3. Routing
  4. ActionResult
  5. GET versus POST actions
  6. Initialising objects for Views
  7. Return Views

The next post will review the Model, View, Controller paradigm based on the code so far before introducing a way to save our new Person to a repository or a database.

No comments:

Post a Comment