This article will guide you through the basic procedure of how to create a simple web application using MVC 6 in ASP.NET 5.
If you stumble onto this article then I assumed you are already familiar with how the old MVC works. I will not be covering the details of MVC itself here so if you are new to ASP.NET MVC then you might want to look at my series of articles below:
• Building Web Application Using Entity Framework and MVC 5: Part 1
• Building Web Application Using Entity Framework and MVC 5: Part 2
• Building Web Application Using Entity Framework and MVC 5: Part 3
MVC 6 the Unified Framework
Figure 1: MVC 6
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 that is the Microsoft.AspNet.Mvc.Controller class.
The merge is also true for HTML helpers in both MVC and Web Pages that are implemented differently before. The Web Pages programming model isn't available yet for the current release 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 is MVC 6 all about and how it differs from the previous versions of ASP.NET MVC we can now go ahead and start digging in. Keep in mind that for this specific demo I'm only covering the MVC stuff.
Let's Begin!
Let's go ahead and fire up Visual Studio 2015 and select File > New > Project. In the New Project dialog select Templates > Visual C# > ASP.NET Web Application. See the following image for a clear view:
Figure 2: ASP.NET Web Application
Name your project whatever you like and then click OK. For the simplicity of this demo I named the project “MVC6Demo”. You should then be able to see the “New ASP.NET Project” dialog as shown in the following image:
Figure 3: Name of the Web Application
The new ASP.NET Project dialog for ASP.NET 4.6 templates allows you to select the type of project you want to create. Configure any combination of technologies such as WebForms, MVC or Web API, configure a unit test project, configure the authentication option and a new option is available to host your website in the Azure cloud. Adding to that, it also provides templates for ASP.NET 5.
In this article I will only be covering the creatiion of an MVC 6 application. So the details of each configuration, like unit testing, authentication, hosting in cloud and so on 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 as in the following image:
Figure 4: Welcome Window
If you have worked with previous versions of ASP.NET before then you will notice that the 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 the web app will serve directly to the clients, including 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 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 concerns, let's create the “Models”, “Views” and “Controllers” folders just like in the following image:
Figure 5: Solution Explorer
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 using 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 that allows developers to plug in components that 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 the project.json file is that it provides intellisense for the available packages when you add or edit dependencies. All packages that you've added from this file will be automatically pulled from NuGet. Correspondingly 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 since we are creating an empty ASP.NET 5 template. To add the MVC dependency to our project just modify the project.json file by adding “Microsoft.AspNet.MVC” under the 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 our application as shown in the following image:
Figure 6: References
Configure the application pipeline
Since we are done with adding the MVC dependency the next step is to add the MVC framework in the pipeline. So open up Startup.cs file and add the following code under the 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 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 up the pieces 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 does all the magic for you. It basically adds the dependencies needed for MVC 6.
Adding Models
Now let's add a simple model that we can test on. For this example I'm creating 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 added the following class 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 a real scenario you may need to get the data from a storage medium such as database or any files that stores your data. It also contains 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 the 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 following image:
Figure 7: Add Controller
Then just 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:
Figure 8: Add View
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<MVC6Demo.Models.DOTAHero>
Output
Figure 9: Output
The following is the simple output from when running the app in the browser.
That's it! Now let's try to look at other new cool features in MVC 6.
Introducing InjectASP.NET MVC 6 has a few new directives that we can use in our application. Here we'll have 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 the 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. GetHeroCount() returns the total count of the heroes and GetHeroCountByType() returns the number of heroes based on a given type. Quite simple and there is nothing much in that class. Here's how to inject the class into 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 to 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 > ();
- }
Running the app will display the following output:
Figure 10: 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 Component to replace widgets that use Html.Action().
View Components also supports fully async allowing you to make a 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 “ViewComponents”. Within that folder create a new class and name it “HeroListViewComponent” and copy the following code:
- 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 the controllers, view components also follow a convention for naming classes. This means that you can create a view component by adding the suffix “ViewComponent” to your class. Adding to that VCs must 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 that 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 a convention too when referencing views. So the first thing to do is to create a new folder within the Home folder. The folder name must be “
Components”. Now since we followed the 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 your class name minus the “ViewComponents” suffix. In this case name the folder
“HeroList”. Finally add a new view within the HeroList folder and name it
“Default” since we didn't specify the view to render in our InvokeAsync code. Your project structure should now look like the following:
Figure 11: Solution Explorer
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>
Running the page will display the following output:
Figure 12: Final Output
That's simple! I hope you will find this article useful. Stay tuned for more!