Content:
1. Introduction
2. Create and run new app (with template)
3. Create and run new empty app
4. View
   - Frame (master file)
   - Inner content
5. Controller
   - Empty app - summary
6. Model
7. Configuration
8. Deployment
9. Application object
10. Navigation among pages
   - Link pointing out of project
11. Routing
12. Routing attributes MVC 5
13. Bundles
14. Rendering
   - Section
   - Partial view
15. Passing arguments
16. Session
17. Cookies
18. Authentication
19. Working with collections (displaying list)
20. Forms
   - Associating style with controls
21. Display a file (like PDF)
22. Debugging remote requests



1. Introduction

Active Server Pages is a technology that helps you build web site that needs to interact with user, guides the user through process, and/or store data.
You can find comprehensive information on the asp.net site.

MVC stands for Model-View-Controller

View:       provides output visible in browser
Controller: processes incoming request
Model:      container for data being presented 
This page describes ASP MVC 2 and shows differences in version 4.

2. Create and run new app (with template)

1. In Visual Studio (2010): Create New project, Web folder, ASP MVC 2 application, Folder for solution-Yes (helps to organize web site and test project under one folder), 
   Create test project - Yes
2. F5 - Build and Run  (opens in IE test instance)
3. If you put a break point to HomeController class, Index method, Visual Studio will stop there.
If you want to explore project creating by ASP MVC 2 template, continue here: MSDN - First ASP MVC 2 App
If you want to follow fundamentals step by step, continue below:


3. Create and run new empty app

In Visual Studio (2010): Create New project, Web folder, ASP MVC 2 Empty Application


4. View

In order to present content in an Internet browser, the ASP MVC has to generate a HTML page. The page that ASP MVC returns consists from 2 parts: frame and inner content.

Frame (master file)

The file representing frame is usually called site.master and located under View/Shared folder

ASP
<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>

<!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>
</head>
<body>
  <h1>My MVC Application</h1>

  <asp:ContentPlaceHolder ID="MainContent" runat="server" />
</body>
</html>
asp:ContentPlaceHolder will present content of the inner page. The entry page, known as Home page, is usually named and located as /Views/Home/Index.aspx

Inner content

ASP
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    My Home Page
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    Hello
</asp:Content>
   MasterPageFile has to refer to the location of the master file
   asp:Content with ContentPlaceHolderID TitleContent is referenced as master page title
   asp:Content with ContentPlaceHolderID MainContent  is referenced as master page content

5. Controller

In order to return the combined site.master and .aspx pages, it is necessary to create connection between incoming http request with specific URL and returned HTML response. This is responsibility of controller and mapping defined in global.asax.cs (MVC 2)

Global.asax.cs gets created by Visual Studio for both Empty and template based applications and defines that Index.aspx gets routed to Controllers\HomeController.cs In order return the combined site.master and .aspx pages, it is necessary to create connection between incoming http request with specific URL and returned HTML response.

Global.asax.cs defines that Index.aspx gets routed to ~/Controllers/HomeController.cs

C#
     new { controller = "Home", action = "Index", id = UrlParameter.Optional } 
Controllers need to be placed under Controllers folder and file named like HomeController.cs

C#
  using System.Web.Mvc;
  public class HomeController : Controller
  {
      public ActionResult Index()
      {
          return View();  // returned View will be ~/Home/Index.aspx
      }
  }
Now you can run the application and you see web site with text Hello.

So far we achieved what we could achieve with simple static HTML page. When we need to pass some generated data to the view then we can leverage ASP MVC. Add the line below into Index() method of the HomeController

C#
   ViewData["MyText"] = "from HomeController";
and extend asp:Content element with ContentPlaceHolderID="MainContent" as below

ASP
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    Hello <%: ViewData["MyText"]%>
</asp:Content>
If you run it now, you will see "Hello from HomeController" in your browser.

In MVC 4, you can use ViewBag

Assign the value in the controller

C#
ViewBag.MyMessage="hello";   
and read it in the view

CSHTML
@ViewBag.MyMessage

Empty app - summary

Add Views/Shared/Site.Master - xHTML site that hosts any site, e.g. Index.aspx as ContentControl 
Add Views/Home/Index.aspx - embedded content
Add Controllers/HomeController.cs - controller for views under Views/Home  
global.asax.cs - created by Visual Studio


6. Model

The issue related to ViewBag or ViewData approach is that compiler does not validate name of and type of the property. This can be solved by using model. Right click on the Models folder and add new class like below. (Models do not have to be located under Models folder.)

C#
public class MyModel
{
    public string MyMessage { get; set; }
}
In the controller, create new instance of MyModel class, set the property and pass to the view

C#
public ActionResult Index()
{
    var model = new MyModel();
    model.MyMessage = "hello model";
    return View(model);
}
You need to update the view:
1. tell the view page about the type of the model in the inherits section, "AspMvcDemo1.Models.MyModel"
2. use any model class property - intellisense works here, but if you make a typo, compiler will not catch it!

ASP
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<AspMvcDemo1.Models.MyModel>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
        MyMessage: <%: Model.MyMessage %>
</asp:Content>
MVC 4 approach in .cshtml

CSHTML
@model AspMvcDemo1.Models.MyModel
...
MyMessage: @Model.MyMessage

7. Configuration

If you need to configure your site, you can use web.config

XML
<appSettings>
  <add key="mykey" value="myValue" />
<appSettings>
retrieve the value in the code as

C#
// in System.Configuration.dll
string myValue = System.Configuration.ConfigurationManager.AppSettings["myKey"];

8. Deployment

See ASP.net on IIS installation in IIS chapter for prerequisites.

Start VS as admin
Right click on the project, Publish
Deployment type: Web deployment (copies files)
Profile: New profile, select name
Server: localhost
Site name: Default Web Site/MyApp

Open IIS (intemgr)
Righ click on MyApp folder and seletc "Convert to application"
Righ click on MyApp folder and select Manage Application\Advanced properties, set Application pool to ASP.net 4.0 (with Integrated pipeline mode) (if you use .net 4)

If the app uses an SQL DB, it may need its own app pool with identity set to the account that has access to the DB (or configure the DB to provide access to the account under which IIS runs)


9. Application object

Application object provides event handlers that can be used to log the information regarding application, session and request lifetime, and unhandled exceptions.
More info: http://sandblogaspnet.blogspot.ch

ASP
public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start() { }
    protected void Application_End() { }

    // Application_BeginRequest
    // Application_EndRequest
    // Application_AuthenticateRequest
    
    void Application_Error(object sender, EventArgs e)
    {
        Exception exc = Server.GetLastError();
        ...
        Server.ClearError();
    }

    void Session_Start(object sender, EventArgs e) { }
    void Session_End(object sender, EventArgs e) { }
 }

10. Navigation among pages

In order to create navigation links to targets within the project, you can use Html.ActionLink

ASP
  <%: Html.ActionLink("TextVisibleToUser", "NameofMethodInController", "ControllerName", new { @myParamName = "abc" } )%>

Link pointing out of project

If you need to create a link that points out of the project where you cannot use @Html.ActionLink that requires controllers and views, you can use @Html.Raw

CSHTML
  @Html.Raw("<a href=\"" + Model.Link + "\">Go here</a>")

11. Routing

Routing is defined global.asax.cs. This file gets created by Visual Studio and it gets populated with default routing. You can add another routing or modify default routing.

C#
public static void RegisterRoutes(RouteCollection routes)
{
    routes.MapRoute(
        "Default", // Route name - has to be unique
        "{controller}/{action}/{id}", // URL with parameters
        new { controller = "Home", action = "Index", id = UrlParameter.Optional } // defaults if URL does not contain all sections, e.g. /Home will use /Home/Index
    );
}

12. Routing attributes MVC 5

MVC 5 introduces new capability that allows to define routing by attributes associated with method. More details can found on MSDN or attributerouting.net

you need to call MapMvcAttributeRoutes()

C#
public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapMvcAttributeRoutes();
    
    // you can still use classic definition here
}
...
public class PersonsController : Controller
{
    // /people will handled by PersonsController
    [Route("people")] 
    public ActionResult View(string id) {...}
}

C#
[RoutePrefix("people")]    // prefix for all actions
[Route("{action=index}")]  // default route  
public class PersonsController : Controller
{
    // /people/id 
    [Route("Id"), name="personById"]  // named route  
    public PersonActionResult View(string id)   {...}
}

..

// named route 
<a href="@Url.RouteUrl("personById")">Person by id</a>

13. Bundles

Bundles make it easier to include scripts and style in a web page
BundleConfig.cs is created by Visaul Studio under App_Start folder

C#
public class BundleConfig
{
    // For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862
    public static void RegisterBundles(BundleCollection bundles)
    {
        bundles.Add(new StyleBundle("~/Content/css").Include(
                  "~/Content/bootstrap.css",
                  "~/Content/Site.css"
                  ));

         bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                   "~/Scripts/jquery-{version}.js"));
    }
}
Defined bundles can be rendered e.g. in Views/Shared/_Layout.cshtml

CSHTML
<html>
<head>
  ...
  @Styles.Render("~/Content/css")
</head>
<body>
  ...
  @Scripts.Render("~/bundles/jquery")
</body>
</code>

14. Rendering

Section

Sections are in detail described here

web page Template is stored in shared/_layout.cshtml

CSHTML
<html>
<body>
@RenderBody();  // includes view content that is not included in section(s) 

@IsSectionDefined("mySection")
{
  @RenderSection("mySection");  // includes specific section
}
else { ... }

@RenderSection("mySection", required:false);  // skips if section does not exist
<body>
<html>
page details are in myview.cshtml that gets embedded into _layout.cshtml

CSHTML
@section mySection {
a html content
}
Section can be used to wrap JavaScript into sections and render them at the end of the template.

Partial view

Partial views allows to share views and include part of html code in other page

CSHTML
<html>
<body>
@Html.Partial("CompanyName");  // includes HTML from myPartialView 
<body>
<html>
CompanyName.cshtml

CSHTML
<h1>Company One</h1>
@ ... another code 

15. Passing arguments

It is still possible to pass arguments to the controller like http://myserver/mysite?personId=1

C#
string myArgValue = Request.QueryString["personId"];   //   myArgValue = 1

16. Session

In a controller code you can use Session, which is collection of values

C#
   this.Session["userId"] = 123;
What can cause session be terminated:
Ternination of all sessions
App pool unexpectedly recycled
SessionState Performance - Myth

17. Cookies

Cookies can be used to store userName.
Write cookie inside the controller processing the request after user clicks the Login button

C#
public class LoginController : Controller 
{
  public ActionResult Login(string userName, string password)
  {
    this.Response.Cookies.Add(new System.Web.HttpCookie("userName", userName));
  }
}
Read cookie when login page gets loaded

C#
public class LoginController : Controller
{
    public ActionResult Index()
    {
      HttpCookie cookie = this.Request.Cookies["userName"];
      if (cookie != null)
      {
          ViewBag.UserName = cookie.Value;
      }
      else
      {
          ViewBag.UserName = string.Empty;
      }
    }
}

18. Authentication

IIS: Windows Authentication must be enabled, Anynomous MUST be disabled

CMD
<system.web>
  <authentication mode="Windows" />
</system.web>

C#
// inside controller (or view) 
string userName = this.Request.LogonUserIdentity.Name;

// alternatively you can use shortcut
string userName = this.User.Identity.Name;

19. Working with collections (displaying list)

In the controller, create new instance of MyModel class, set the property and pass it to the view

C#
public ActionResult Index()
{
    List<Person> people = new List<Person>();
    people.Add(new Person() { Name = "Paul", Height=178 });
    people.Add(new Person() { Name = "George", Height=182 });
    return View(people);
}
You need to update the view to describe type that will hold the collection as List<"AspMvc2Empty.Models.Person">

ASP
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<List<AspMvc2Empty.Models.Person>>" %>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

   <table>
    <% foreach (var item in Model) {%>

       <tr>
       
           <td> <%: item.Name %> </td>

           <td> <%: item.Height %> </td>
       
       </tr>

    <% } %>

    </table>

</asp:Content>
or in MVC 4 with Razor syntax

CSHTML
@model List<AspMvcBasics.Models.Person>
@{
    ViewBag.Title = "People";
}
<table>
    @foreach (var item in Model)
    {
        <tr>
            <td>
                @item.Name
            </td>
            <td>
                @item.Height
            </td>
        </tr>
    }
</table>

20. Forms

If it is necessery to collect data from user like login, instead of using HTML tags APS MVC provide @Html classes that can be used instead of HTML tags. The example below uses MVC 4 Razor syntax.
If the form contain a ListBox, it necessary to pass data to feed the ListBox

C#
public class LoginController : Controller
{
    public ActionResult PrepareLogin()
    {
        // data for list box
        SelectList selection = new SelectList(
        new[] { 
                new { Value = "A", Text = "Team A" }, 
                new { Value = "B", Text = "Team B" }, 
                new { Value = "C", Text = "Team C" }, 
            },
        "Value",
        "Text"
        );

        return View(selection);
    }
 }   
Code in the view could look like below

CSHTML
@model SelectList
@using (Html.BeginForm("HandleLogin", "Login"))
{
  User name: @Html.TextBox("userName", "JohnFirst")
  Password: @Html.Password("password")
  
  Remember me: @Html.CheckBox("rememberUserName", false)
  
  @Html.RadioButton("server", "s1", true) @:Server 1
  @Html.RadioButton("server", "s2", false ) @:Server 2
  
  @Html.ListBox("team", Model, new { size = 20 } )
  
  <input type="submit" value="Login" />
}
Note: when RadioButton is inside a container (div, td) then @: must be ommited

Wenn uses clicks "Login", the action called will the Index method in HomeController and values from input elements will be passed as arguments.

C#
public class LoginController : Controller
{
    public ActionResult HandleLogin(string userName, string password, 
         string rememberUserName, string server, string team)
    {
      ....
      return View();
    }
 }   

Associating style with controls

C#
@Html.TextBox("userName", (string)ViewBag.UserName, new { @class = "k-textbox" } )

21. Display a file (like PDF)

In order to display content of file like PDF it necessary that an Action returns content of the file. It can be achieved with FilePathResult, FileContentResult or FileStreamResult.

C#
public FilePathResult Report()
{
    return new FilePathResult(@"c:\myfolder\myfile.pdf", "application/pdf");
}

// The FileContentResult approach enables file deletion in case the file was generated 
public FileContentResult Report()
{
  byte[] content = System.IO.File.ReadAllBytes(@"c:\myfolder\myfile.pdf");
  System.IO.File.Delete(@"c:\myfolder\myfile.pdf");
  return new FileContentResult(content, "application/pdf");
}

22. Debugging remote requests

When you start debugging an ASP MVC application, Visual Studio starts c:\Program Files (x86)\Common Files\Microsoft Shared\DevServer\11.0\WebDev.WebServer40.EXE or WebDev.WebServer20.EXE based on .net you use.

This is a Dev server that is sometimes called as Cassini and it does not accept requests from remote machines.

In order to be able to debug request coming from remote machines, you can install Fiddler and setup it as a proxy
on the machine where you have Visual Studio.
- In Fiddler, Tools > Fiddler Options, tab Connections, ensure that Allow remote clients to connect is set
- Close Fiddler
- Create a new HKEYCURRENTUSER\SOFTWARE\Microsoft\Fiddler2\ReverseProxyForPort of type DWORD and set the its decimal value to the port that you see in Internet Explorer that was opened by Visual Studio when you started debugging (usually above 30000, e.g. ).
- Start Fiddler.
- Start debugging your application
- In a browser (local or remote machine), go to http://{computer name}:{port above 30000}/{SpecificPage}
- If you set a breakpoint inside a web service method in Visual Studio, Visual Studio will stop the request execution there