ProudMonkey

ASP.NET 5 - Getting Started with ASP.NET MVC 6

This article will guide you through the basic steps on how to create a simple web application using MVC 6 in ASP.NET 5.

If you stumble into this article then I assume you are already familiar about how the old MVC works. I will not be covering the details about MVC itself here so if you are new to ASP.NET MVC then you might want to look at my series of articles below:

MVC 6 the Unified Framework

ASP.NET 5 will see MVC, Web API and Web Pages combined into one framework called MVC 6.

In previous versions of ASP.NET MVC, MVC controllers were different from Web API controllers. An MVC controller used the System.Web.MVC.Controller base class and a Web API controller used the System.Web.Http.ApiController base class. In MVC 6, there is only one Controller base class for both MVC and Web API controllers which is the Microsoft.AspNet.Mvc.Controller class.

The merge is also true for HTML helpers in both MVC and Web Pages which are implemented differently before. The Web Pages programming model isn't available yet for the current release (ASP.NET 5 Preview) so we can never really tell what will be the other features that they're going to merge, but we can assume that the traditional MVC model-binding will be available to it.

Now that you already have an idea of what MVC 6 is all about and how does it differs to previous versions of ASP.NET MVC, we can go ahead and start digging. Keep in mind that for this particular demo I’m only be covering about the MVC stuff.

Let’s Begin!

Let’s go ahead and fire up Visual Studio 2015 and select File > New > Project. Under New Project dialog select Templates > Visual C# > ASP.NET Web Application. See image below for a clear view:

Name your project to whatever you like and then click OK. For the simplicity of this demo I named the project as “MVC6Demo”. Now after that you should be able to see the “New ASP.NET Project” dialog:

The new ASP.NET Project dialog for ASP.NET 4.6 templates allows you to select what type of project you want to create, configure any combination of technologies such as WebForms, MVC or Web API, configure unit test project, configure authentication option and also offers a new option to host your website in the Azure cloud. Adding to that it also provide templates for ASP.NET 5.

In this article I will only be covering on creating an MVC 6 application. So the details of each configuration like unit testing, authentication, hosting in cloud, etc. will not be covered.

The goal here is to build an MVC 6 application from scratch so select ASP.NET 5 Empty template from the dialog above. Then click OK to let Visual Studio generate the necessary files and templates needed for you.

You should be able to see something like below:
If you are working with previous versions of ASP.NET before then you will notice that new project structure is totally different. The project now includes these files:

  • src folder – contains all projects that contain source code that make up your application.
  • global.json – this is where you put solution-level settings, and allows you to do project-to-project references.
  • wwwroot - is a folder in which all your static files will be placed. These are the assets that you web app will serve directly to the clients uncluding HTML, CSS, Image and JavaScript files.
  • project.json – contains project settings
  • startup.cs – this is where you put your startup and configuration code.

For details about the new features in ASP.NET 5 then check out this article: Introducing ASP.NET 5: The New ASP.NET in Town!

Setting up the MVC folder structures

To follow the MVC standard pattern and the separation of concern, let’s create the “Models”, “Views” and “Controllers” folders just like in the image below:

Another important thing to talk about is the References folder. By default it contains ASP.NET 5.0 and ASP.NET Core 5.0 references. These enables you to choose what .NET runtime you’ll be going to use in your project. The new ASP.NET 5.0 or the .NET Full CLR enables you to utilize all the .NET components that are available and supports backward compatibility. The ASP.NET Core 5.0 or .NET Core CLR is a refactored version of .NET. It was redesigned to be modular which allows developers to plug components which are only required for your project and it is a cloud optimized runtime.

Introducing the project.json file

The project.json file serves as the new project file (.csproj/.vbproj). This is where we put all the dependencies that our application requires.
The cool thing about project.json file is that it provides intellisense for the available packages while you add or edit dependencies. All packages that you’ve added from this file will automatically pulls the packages from NuGet. At the same when you remove packages it automatically removes them from your project reference. That’s pretty awesome!

Up to this point there’s really no MVC in our app yet as we are creating an empty ASP.NET 5 template. To add the MVC dependency in our project just modify the project.json file by adding “Microsoft.AspNet.MVC” under dependencies section. Your project.json should look like this:

    "webroot": "wwwroot",
    "version": "1.0.0-*",
    "dependencies": {
        "Microsoft.AspNet.Server.IIS": "1.0.0-beta3",
        "Microsoft.AspNet.Mvc": "6.0.0-beta3"
    },
    "frameworks": {
        "aspnet50": { },
        "aspnetcore50": { }
    },

As of this writing MVC 6.0.0.0-beta3 is the latest beta version. Now save the project.json file to restore NuGet packages. The MVC framework should now be added to your application as shown in the image below:

Configure the application pipeline

Since we’ve done adding the MVC dependency then the next step is to add the MVC framework in the pipeline. So open up Startup.cs file and add the following code below under Configure method:

public void Configure(IApplicationBuilder app) {  
            app.UseMvc(m => {
                m.MapRoute(
                    name: "default",
                    template: "{controller}/{action}/{id?}",
                    defaults: new { controller = "Home", action="Index"});
            });
}

The code above is pretty much the same as the old MVC for defining routes, except that we are now using the UseMvc method to setup the routes.

We’re not done yet

Adding the MVC in the pipeline doesn’t mean that we are now good to go. We still need to hook the spices of MVC by adding the dependencies that MVC 6 requires. So your ConfigureServices method should now look like this:

public void ConfigureServices(IServiceCollection services) {  
            services.AddMvc();
}

The AddMvc() is an extension method that do all the magic for you. It basically adds dependencies needed for MVC 6.

Adding Models

Now let’s add a simple model that we can test on. For this example I created the following class under the “Models” folder:

using System;

namespace MVC6Demo.Models  
{
    public class DOTAHero
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public string Type { get; set; }
    }
}

And then created the following class below that manages the “DOTAHero” class:

using System.Collections.Generic;  
using System.Linq;

namespace MVC6Demo.Models  
{
    public class HeroManager {

        readonly List<DOTAHero> _heroes = new List<DOTAHero>() {
            new DOTAHero { ID = 1, Name = "Bristleback", Type="Strength"},
            new DOTAHero { ID = 2, Name ="Abbadon", Type="Strength"},
            new DOTAHero { ID = 3, Name ="Spectre", Type="Agility"},
            new DOTAHero { ID = 4, Name ="Juggernaut", Type="Agility"},
            new DOTAHero { ID = 5, Name ="Lion", Type="Intelligence"},
            new DOTAHero { ID = 6, Name ="Zues", Type="Intelligence"},
            new DOTAHero { ID = 7, Name ="Trent", Type="Strength"},
        };
        public IEnumerable<DOTAHero> GetAll { get { return _heroes; } }

        public List<DOTAHero> GetHeroesByType(string type) {
            return _heroes.Where(o => o.Type.ToLower().Equals(type.ToLower())).ToList();
        }
    }
}

The HeroManager class contains a readonly property that contains a list of heroes. For simplicity, the data is obviously static. In real scenario you may need to get the data in a storage medium such as database or any files that stores your data. It also contain a GetAll property that returns all the heroes and finally a GetHeroesByType() method that returns a list of heroes based on the hero type.

Adding a Controller

Adding a controller is pretty much the same as adding controllers in old MVC. Just right click on the “Controllers” folder and then select Add > New Item. In the dialog select MVC Controller Class as shown in the image below:

Now go ahead and click Add to generate the controller class for you. Here’s the HomeController class:

using Microsoft.AspNet.Mvc;  
using MVC6Demo.Models;

namespace MVC6Demo.Controllers  
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            HeroManager HM = new HeroManager();
            var heroes = HM.GetAll;

            return View(heroes);
        }
    }
}

There’s nothing really fancy in the code above. It’s just a controller that contains an IActionResult() method that returns the list of heroes that is coming from the model.

Adding a View

Right clicking on the controller’s action name doesn’t bring up the “Add New Item” dialog. So to add views just do the same thing as what we did for adding the controller. But before that we must add a “Home” folder under the “Views” folder to follow the MVC convention. Right click on the “Home” folder and select Add > New Item > MVC View Page:

Click add to generate the file. Now there’s no magic in creating our view since we didn’t use any scaffolding template. Instead we need to setup the view by hand. Here’s what my view looks like:

@model IEnumerable<MVC6Demo.Models.DOTAHero>

<h3>My Favorite DOTA Heroes</h3>  
<ul>  
    @foreach (var p in Model) {
        <li>@string.Format("{0} {1}", p.Name, p.Type)</li>
    }
</ul>  

The view above is a strongly-typed view. By including a @model statement at the top of the view template file, you can specify the type of object that view expects. In this case it uses the IEnumerable

Output

Here’s the simple output below when running the application in the browser:
That’s it! Now let’s try to look at other new cool features in MVC 6.

Introducing Inject

ASP.NET MVC 6 has few new directives that we can use in our application. Here we’ll take a look at how to use @inject. The @inject directive allows you to inject some method calls from a class or service directly into your view. To see that in action I’ve created a new class called “HeroStats” under Models folder. Here’s the simple class that exposes some async methods:

using System.Linq;  
using System.Threading.Tasks;

namespace MVC6Demo.Models  
{
    public class HeroStats
    {
        private HeroManager _manager = new HeroManager();

        public async Task<int> GetHeroCount() {
            return await Task.FromResult(_manager.GetAll.Count());
        }

        public async Task<int> GetHeroCountByType(string type) {
            return await Task.FromResult(_manager.GetHeroesByType(type).Count);
        }

    }
}

The class above initializes a new instance of HeroManager. It also contains two main async methods; The GetHeroCount() returns the total count of the heroes and the GetHeroCountByType() returns the number of heroes based on a given type. Pretty much simple and there nothing much on that class. Here’s how to inject a class in the View:

@model IEnumerable<MVC6Demo.Models.DOTAHero>
    @inject MVC6Demo.Models.HeroStats Stats

<h3>My Favorite DOTA Heroes</h3>  
<ul>  
    @foreach (var p in Model) {
        <li>@string.Format("{0} {1}", p.Name, p.Type)</li>
    }
</ul>

<div>  
    <span>Number of Strength: @await Stats.GetHeroCountByType("strength")</span><br/>
    <span>Number of Agility: @await Stats.GetHeroCountByType("agility")</span><br/>
    <span>Number of Intelligence: @await Stats.GetHeroCountByType("intelligence")</span><br />
    <span>Total Heroes: @await Stats.GetHeroCount()</span>
</div>  

Now in order for it work we need to configure the AddTransient() method by adding the HeroStats model into it. So the Configure method would now look like this:

public void ConfigureServices(IServiceCollection services)  
{
            services.AddMvc();
            services.AddTransient<MVC6Demo.Models.HeroStats>();
}

Output

Running the application will display the following output:

Introducing View Components

Another cool feature in MVC 6 is the “View Components”. If you remember, in previous versions of ASP.NET MVC, the Html.Action() helper is typically used to invoke a sub-controller. A sub-controller may display stuff like tag clouds, dynamic links, side bars or whatever. ASP.NET MVC 6 introduced the new View Components to replace widgets that uses Html.Action().

View Components also supports fully async allowing you to make view component asynchronous.

Now let’s try to create a very simple view component and let’s see how they are used in MVC. To start, create a new folder at the root of your application and name it as “ViewComponents”. Within that folder create a new class and name it as “HeroListViewComponent” and copy the following code below:

using Microsoft.AspNet.Mvc;  
using System.Threading.Tasks;  
using MVC6Demo.Models;  
using System.Collections.Generic;

namespace MVC6Demo.ViewComponents  
{
    public class HeroListViewComponent : ViewComponent
    {
        public async Task<IViewComponentResult> InvokeAsync(string type) {
            var heroes = await GetHeroesAsync(type);
            return View(heroes);
        }

        private Task<IEnumerable<DOTAHero>> GetHeroesAsync(string type) {
            return Task.FromResult(GetHeroes(type));
        }

        private IEnumerable<DOTAHero> GetHeroes(string type) {
            HeroManager HM = new HeroManager();
            return HM.GetHeroesByType(type);
        }
    }
}

Just like controllers, view components also follow convention when naming classes. This means that you can create view component by adding the suffix “ViewComponent” in your class. Adding to that VCs must also be public, non-nested and non-abstract classes.

Notes:
  • You can also use the [ViewComponent] attribute in your class when referencing a ViewComponent.

  • You can use the overload method of the View() to specify a view to render from your InvokeAsync method. For example return View(“YourViewName”,model).

The InvokeAsync exposes a method which can be called from a view, and it can take an arbitrary number of arguments. As you have seen from the code above we passed in the parameter “type” in the method to filter the data.

Now let’s add the view for the View Component that we just have created. Keep in mind that VC follows convention too when referencing views. So the first thing to do is create a new folder within Home folder. The folder name must be “Components”. Now since we followed convention in our example, the next thing to do is to create another new folder within the Components folder, this time the folder name must match with your class name minus the “ViewComponents” suffix. In this case name the folder as “HeroList”. Finally add a new view within HeroList folder and name it as “Default” since we didn’t specify the view to render in our InvokeAsync code. Your project structure should now look like this:

In your Default.cshtml file, add the following markup for your View Component’s view:

@model IEnumerable<MVC6Demo.Models.DOTAHero>

<h3>Strength Heroes</h3>  
<ul>  
    @foreach (var p in Model) {
        <li>@p.Name</li>
    }
</ul>  

And here’s how we call the View Component from the main view (Index.cshmtl):

<div>  
    @await Component.InvokeAsync("HeroList", "strength")
</div>  

Output

Running the page will display the following output:

That’s simple! I hope you will find this post useful. Stay tuned for more!