Language

Getting Started with ASP.NET MVC 6

By Mike Wasson|

The next version of ASP.NET (“ASP.NET vNext”) has been re-designed from the ground up. The goal is to create a lean and composable .NET stack for building modern cloud-based apps.

This tutorial describes the new ASP.NET MVC 6 framework, which unifies MVC, Web API, and Web Pages.

As part of ASP.NET vNext, the MVC, Web API, and Web Pages frameworks are being merged into one framework, called MVC 6. The new framework removes a lot of overlap between the existing MVC and Web API frameworks. It uses a common set of abstractions for routing, action selection, filters, model binding, and so on. You can use the framework to create both UI (HTML) and web APIs.

This overview assumes you are familiar with either MVC 5 or Web API 2. If not, here is some terminology that is used in ASP.NET MVC.

  • A controller handles HTTP requests and executes application logic.
  • Actions are methods on a controller that get invoked to handle HTTP requests. The return value from an action is used to construct the HTTP response.
  • Routing is the mechanism that selects which action to invoke for a particular HTTP request, usually based on the URL path and the HTTP verb.
  • A view is a component that renders HTML. Controllers can use views when the HTTP response contains HTML.
  • A model is an object that represents the domain data in your application. Typically an app either renders the model as HTML, or serializes the model into a data format such as JSON.
  • Razor syntax is a simple programming syntax for embedding server-based code in a web page.

I've defined some of these terms in a way that is specific to ASP.NET. For example, controllers have a particular purpose in ASP.NET MVC, but “model-view-controller” is a more general pattern, used by many frameworks.

You can use Visual Studio "14" to create and build MVC 6 projects. For more information, see Getting Started with ASP.NET vNext and Visual Studio "14". You can also build and run an MVC 6 application from the command line. To use the command-line tools, you first need to follow the instructions on the project wiki.

A minimal vNext project contains two files:

  • project.json. This file lists the dependencies for the application.
  • A startup class. This class is where you configure the HTTP request pipeline for your application.

If you are using Visual Studio "14", create these files by using the ASP.NET vNext Empty Web Application template. Otherwise, you can just create them manually in a folder. For example:

  1. In a working folder of your choice, create a text file named project.json and copy the following text into it:
    {
        "webroot" : "wwwroot",
        "exclude": "wwwroot/**/*.*",
        "dependencies": {
            "Microsoft.AspNet.Diagnostics": "1.0.0-alpha4",
            "Microsoft.AspNet.Hosting": "1.0.0-alpha4",
            "Microsoft.AspNet.Server.WebListener": "1.0.0-alpha4",
            "Microsoft.AspNet.Server.IIS": "1.0.0-alpha4"
        },
        "commands": {
            "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5001"
        },
        "frameworks": {
            “aspnet50”: {},
            “aspnetcore50”: {}
        }
    }
    
    Note:The package Microsoft.AspNet.Server.IIS is only needed if you create project.json in an ASP.NET vNext Empty Web Application project, and want to use IIS Express to debug your application.
  2. In the same folder, create another text file called Startup.cs and copy the following text into it:
    using Microsoft.AspNet.Builder;
    
    public class Startup
    {
        public void Configure(IApplicationBuilder app)
        {
            app.UseWelcomePage();
        }
    }
    
  3. Add a wwwroot folder. This folder is where you would put any static files that you want to include with your application. You can leave it empty for now.

By default , the hosting environment expects the startup class to be named Startup. The startup class must contain a method named Configure with the signature shown here. Inside this method, use the IApplicationBuilder interface to configure the application.

The UseWelcomePage methods adds a middleware component that just displays a welcome page. The welcome page is useful for diagnostic purposes, to make sure your project is configured and running correctly.

Note: If you created these files using the ASP.NET vNext Empty Web Application template, you can simply click Run to run the application. But regardless whether you created the files in Visual Studio "14" or manually in a text editor, you have the option of running it without IIS or IIS Express. I will show you how to do this.

To self-host the simple application you created with a lightweight web listener in the command prompt, first follow the steps below:

  1. Run the following command from a command prompt to install the K Version Manager.
    @powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/aspnet/Home/master/kvminstall.ps1'))"

    Note: For updated instructions and for information on running it on other platforms, such as OS X and Linux, see ASP.NET vNext Home > Getting Started

  2. Open a new command line session to load the new environment variables.
  3. In the command prompt, run the following commands:
    kvm install 1.0.0-alpha4 
    cd <PROJECT.JSON_FOLDER>
    kpm restore
    

The kvm install command installs the specified version of the ASP.NET vNext runtime. The kpm restore command resolves the dependencies listed in the project.json file, and downloads the necessary NuGet packages.

The kpm tool will restore packages using the package feeds specified in your NuGet package manager settings. The ASP.NET vNext packages are currently available from the package feed at https://www.myget.org/F/aspnetmaster/

Once you finish running the commands, you will be able to self-host the application from the command prompt. To do this, simply type:

k web

The k web command starts the HTTP listener. Notice there is no explicit build step. The k web command compiles the code on the fly. After you install the NuGet packages, you can make changes to the code and run k web again, without running kpm restore.

Next, launch a browser and navigate to http://localhost:5001. You should see the welcome page.

The web command is defined in the project.json file:

 "commands": {
        "web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5001"
},

This command starts the hosting environment and listens on the specified localhost address. You can edit the project.json file to use a different port number.

Serving Static Files

The welcome page is not too interesting, so let’s enable the app to serve static files. Add the following entry to the “dependencies” section of the project.json file and run kpm restore to get the required packages.

"Microsoft.AspNet.StaticFiles": "1.0.0-alpha4"

Modify the Startup class as follows.

using Microsoft.AspNet.Builder;
using Microsoft.AspNet.StaticFiles;

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.UseStaticFiles();
    }
}

The static file middleware will now handle requests to files on disk in your application such as images, script files, style sheets, etc. Static files should be placed in your application’s wwwroot folder as specified in the project.json file.

Getting Started with MVC 6

In the rest of this overview, we’ll explore some of the features of MVC 6. To enable MVC, first add the following entry to the "dependencies" section of the project.json file and run kpm restore to get the required packages:

"Microsoft.AspNet.Mvc": "6.0.0-alpha4"

Then, modify the Startup class as follows.

using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Builder;
using Microsoft.Framework.DependencyInjection;

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.UseServices(services =>
        {
            services.AddMvc();
        });

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "Default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });

    }
}

This code enables MVC and defines a route. If you’ve used earlier versions of MVC, the MapRoute method should look familiar. For comparison, here are the same routes defined in MVC 5 and MVC 6:

// MVC 5 route
routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", 
        id = UrlParameter.Optional }
);

// MVC 6 route
routes.MapRoute(
    name: "Default",
    template: "{controller=Home}/{action=Index}/{id?}"
);

Notice that in MVC 6 you can specify default route values inline in the route template. The ‘?’ character in the template means the {id} segment is optional.

Next, add a controller class. The following controller defines a single action named Index that returns a view.

using Microsoft.AspNet.Mvc;

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }
}

Except for the namespace, this code would compile in MVC 5.

Now add a view. Create a file named .\Views\Home\index.cshtml and paste in the following code.

@{
  var message = "Hello World";
}

<!DOCTYPE html>

<html lang="en">
<head>
  <meta charset="utf-8" />
  <title>Index Page</title>
</head>
<body>
  <h1>@message</h1>
  <p>Index page</p>
</body>
</html>

I included a @message variable just to show that this is a Razor file and not just static HTML.

Here is the file structure for your working folder or Visual Studio project:

.\HomeController.cs
.\project.json
.\Startup.cs
.\Views\Home\Index.cshtml
.\wwwroot

Run the app by using the k web command, and then navigate to http://localhost:5001. You should see the HTML that is rendered by the Index view.

View Models

You can pass a model to the view. Let’s add a model class:

public class MessageModel
{
    public string Message { get; set; }
}

Modify the action by passing an instance of MessageModel to the View method:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new MessageModel { Message = "Hello ASP.NET" };
        return View(model);
    }
}

Update index.cshtml to refer to the model.

<!DOCTYPE html>

<html lang="en">
<head>
  <meta charset="utf-8" />
  <title>Hello World Page</title>
</head>
<body>
  <h1>@Model.Message</h1>
</body>
</html>

Now when you run the app, "Hello ASP.NET" is rendered inside the H1 tag.

Creating Web APIs and REST-Style Actions

If the route template does not include {action}, the framework uses the HTTP verb to select the action name. This style of routing is similar to convention-based routing in the current version of ASP.NET Web API, and is useful for REST-style APIs.

Here is an example of a route template without an {action} variable.

app.UseMvc(routes =>
{
    routes.MapRoute("ApiRoute", "{controller}/{id?}");
});

Using this route template, the action name maps to the HTTP verb in the request. For example, a GET request will invoke a method named Get, a PUT request will invoke a method named Put, and so forth. The {controller} variable still maps to the controller name.

The following controller uses this style of routing.

using Microsoft.AspNet.Mvc;

public class ValuesController : Controller
{
    // GET /values
    public string Get()
    {
        return "Values";
    }

    // GET /values/1
    public string Get(int id)
    {
        return "Value " + id.ToString();
    }

    // POST /values
    public ActionResult Post()
    {
        return new HttpStatusCodeResult(201);
    }
}    

The following table shows the web API that is defined by ValuesController.

Request MethodURI PathController Action
GET/valuesGet
GET/values/1Get(id)
POST/valuesPost

The two Get actions both return strings. In that case, the framework writes the string into the body of the HTTP response, and sets the Content-Type header to “text/plain”. For example, if you send a GET request to /values/1, the response will look similar to the following.

HTTP/1.1 200 OK
Content-Type: text/plain
Server: Microsoft-HTTPAPI/2.0
Date: Wed, 30 Apr 2014 00:16:38 GMT
Content-Length: 7

Value 1

The Post action returns an HttpStatusCodeResult. The framework translates this into an HTTP status code.

HTTP/1.1 201 Created
Content-Length: 0
Server: Microsoft-HTTPAPI/2.0
Date: Wed, 30 Apr 2014 00:18:58 GMT

If you are familiar with ASP.NET Web API, you may have noticed that ValuesController derives from Controller, not ApiController. That’s because vNext does not have a separate controller class for web APIs.

In the current ASP.NET framework, MVC 5 and Web API 2 use completely different classes and namespaces. That means a controller is either an MVC controller or a Web API controller. Web API controllers use separate routes, and they can't use MVC filters or MVC model binders.

One goal of ASP.NET vNext is to merge MVC and Web API into a single framework, which shares a single pipeline and uses the same routing, action selection, filters, model binding, and so forth. The result is a more consistent programming model, and code that is more re-usable.

Returning Formatted Data

You can return an object from your action and let the framework select the appropriate response format based on the request headers and the available formatters. This process is called content-negotiation. For example, let’s add a model class named Movie.

public class Movie
{
    public string Title { get; set; }
    public int Year { get; set; }
    public string Genre { get; set; }
}

Here is a controller that returns a list of movies in JSON format.

using Microsoft.AspNet.Mvc;

public class MoviesController : Controller
{
    public Movie Get()
    {
        var movie = new Movie
        {
            Title = "Maximum Payback", Year = 1990, Genre = "Action"
        };
        return movie;
    }
}

The response from the Get action will look similar to the following.

HTTP/1.1 200 OK
Content-Type: application/json
Server: Microsoft-HTTPAPI/2.0
Date: Thu, 25 Sep 2014 04:53:16 GMT
Content-Length: 120

[{"Title":"Maximum Payback","Year":1990,"Genre":"Action"}]

If the client requests XML then the response will look like this:

HTTP/1.1 200 OK
Content-Type: application/xml
Server: Microsoft-HTTPAPI/2.0
Date: Thu, 25 Sep 2014 04:53:16 GMT
Content-Length: 195

<Movie xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/test.Models"><Genre>Action</Genre><Title>Maximum Payback</Title><Year>1990</Year></Movie>

Alternatively you can return just JSON from your action by calling the Controller.Json method. This method returns a JsonResult, which is an action result that serializes an object to the JSON format.

Areas

Areas are a way to group controllers, models, and views. In previous versions of MVC, you register areas by calling AreaRegistration.RegisterAllAreas. Area controllers are placed in a special Areas folder.

In MVC 6, you create a route template with an {area} parameter, and then decorate area controllers with the [Area] attribute. The following code defines an area route.

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "AreasRoute",
        template: "{area}/{controller}/{action}");

    routes.MapRoute(
        name: "Default",
        template: "{controller=Home}/{action=Index}/{id?}");
});

Given these routes, you could define two Home controllers, as follows:

namespace MyApp.Controllers
{ 
    public class HomeController : Controller
    {
        // Home/Index
        public ActionResult Index()
        {
            return View();
        }
    }
}
namespace MyApp.Areas.Controllers
{
    [Area("Books")]
    public class HomeController : Controller
    {
        // Books/Home/Index
        public ActionResult Index()
        {
            return View();
        }
    }
}

The second controller is assigned to the Books area.

URIController
/Home/IndexMyApp.Controllers.HomeController
/Books/Home/IndexMyApp.Areas.Controllers.HomeController

Views for an area go into a folder named “Areas/{area name}/Views/{controller}”. So in this example, the view for the Books/Home/Index action would go in a file named “Areas\Books\Views\Home\index.cshtml”.

Previously, the Web API framework did not support areas. Because MVC 6 merges the two frameworks, you can now organize web API-style controllers into areas.

View Components and Child Views

View components are similar to child actions in previous versions of MVC. They allow a view to invoke an action and render the result within the view. The following code shows a simple view component that writes a text string.

[ViewComponent(Name = "MyViewComponent")]
public class SimpleViewComponent : ViewComponent
{
    public IViewComponentResult Invoke(int num)
    {
        var message = String.Format("The secret code is: {0}", num);
        return Content(message);
    }
}

To include this view component in a view, call Html.Component.

<html lang="en">
<head>
  <meta charset="utf-8" />
  <title>Index Page</title>
</head>
<body>
  <p>@Component.Invoke("MyViewComponent", 42)</p>
</body>
</html>

When the view is rendered, the p tag will contain the string "The secret code is 42". Notice that you can pass parameters to the view component’s Invoke method.

POCO Controllers

In MVC 6, controllers do not need to derive from Microsoft.AspNet.Mvc.Controller. You can write a controller as a simple class or “POCO” (plain old CLR object). Here is an example.

public class HomeController
{
    // Use the ActivateAttribute to inject services into your controller
    [Activate]
    public ViewDataDictionary ViewData { get; set; }

    public ActionResult Index()
    {
        return new ViewResult() { ViewData = ViewData };
    }
}

ViewData is a dictionary object that you put data into, which then becomes available to the view. Notice that the view data is injected into the controller through the ViewData property by marking the property with the ActivateAttribute.

Previously, I showed a controller calls Controller.View to return a view. That method is really just syntactic sugar for returning a ViewResult.

The Controller class also gives you convenient access to the HTTP request context, the current principal (IPrincipal), a view bag, and other useful properties. So the Controller class is certainly useful, but it’s not required. For a light-weight controller, you might prefer a POCO controller.

Providing Feedback

Feedback is welcome. You can provide feedback in GitHub, in comments on this page, or in the ASP.NET VNext forum. If you ask a question in StackOverflow, use the asp.net-vnext tag. You can make suggestions for new features on the UserVoice site.

This article was originally created on October 6, 2014

Author Information

Mike Wasson

Mike Wasson – Mike Wasson is a programmer-writer at Microsoft.