Build Your First ASP.NET MVC 6 Web Application – Windows ASP.NET Core Hosting 2024 | Review and Comparison

Let’s continue talk about the newest ASP.NET Core 1/MVC 6. Previously, we wrote about how to publish ASP.NET Core 1 in shared hosting environment. In this tutorial, we will continue our journey and we will show how to create simple web application using 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.

How to Create Simple Web Application Using MVC 6

Create your First Project

The first step is open your Visual Studio 2015 –> select File –> New Project. You don’t have Visual Studio 2015, then please download it first.

image_1

Now select the template named “ASP.NET 5 Empty” as the image below, this template is an empty template with no core dependencies on any framework.

image_2

Adding the Dependencies

We’ve used to manage packages/dependencies by using NuGet package manager, and you can do this with the new enhanced NuGet package manager tool which ships with VS 2015, but in our case we’ll add all the dependencies using the “project.json” file and benefit from the IntelliSense provided as the image below:

image_3

So we will add the dependencies needed to configure our Web API, so open file “project.json” and replace the section “dependencies” with the section below:

"dependencies": {
        "Microsoft.AspNet.Server.IIS": "1.0.0-beta1",
        "EntityFramework": "7.0.0-beta1",
        "EntityFramework.SqlServer": "7.0.0-beta1",
        "EntityFramework.Commands": "7.0.0-beta1",
        "Microsoft.AspNet.Mvc": "6.0.0-beta1",
        "Microsoft.AspNet.Diagnostics": "1.0.0-beta1",
        "Microsoft.Framework.ConfigurationModel.Json": "1.0.0-beta1"
    }

Last thing we need to add to the file “project.json” is a section named “commands” as the snippet below:

"commands": {
        "ef": "EntityFramework.Commands"
}

Adding config.json configuration file

Now right click on your project and add new item of type “ASP.NET Configuration File” and name it “config.json”, you can think of this file as a replacement for the legacy Web.config file, for now this file will contain only our connection string to our SQL DB, I’m using SQL Express here and you can change this to your preferred SQL server.

{
    "Data": {
        "DefaultConnection": {
            "Connectionstring": "Data Source=.\\sqlexpress;Initial Catalog=RegistrationDB;Integrated Security=True;"
        }
    }
}

Configure ASP.NET 5 Pipeline

This is the class which is responsible for adding the components needed in our pipeline, currently with the ASP.NET 5 empty template, the class is empty and our web project literally does nothing, I’ll add all the code in our Startup class at once then describe what each line of code is responsible for, so open file Startup.cs and paste the code below:

using System;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Hosting;
using Microsoft.Framework.ConfigurationModel;
using Microsoft.Framework.DependencyInjection;
using Registration_MVC6WebApi.Models;
 
namespace Registration_MVC6WebApi
{
    public class Startup
    {
        public static IConfiguration Configuration { get; set; }
 
        public Startup(IHostingEnvironment env)
        {
            // Setup configuration sources.
            Configuration = new Configuration().AddJsonFile("config.json").AddEnvironmentVariables();
        }
        public void ConfigureServices(IServiceCollection services)
        {
            // Add EF services to the services container.
            services.AddEntityFramework().AddSqlServer().AddDbContext<RegistrationDbContext>();
 
            services.AddMvc();
 
            //Resolve dependency injection
            services.AddScoped<IRegistrationRepo, RegistrationRepo>();
            services.AddScoped<RegistrationDbContext, RegistrationDbContext>();
        }
        public void Configure(IApplicationBuilder app)
        {
            // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
            app.UseMvc();
 
            app.UseWelcomePage();
 
        }
    }
}

Adding Models, Database Context, and Repository

Now we’ll add a file named “Course” which contains two classes: “Course” and “CourseStatusModel”, those classes will represents our domain data model, so for better code organizing add new folder named “Models” then add the new file containing the the code below:

using System;
using System.ComponentModel.DataAnnotations;
 
namespace Registration_MVC6WebApi.Models
{
    public class Course
    {
        public int Id { get; set; }
        [Required]
        [StringLength(100, MinimumLength = 5)]
        public string Name { get; set; }
        public int Credits { get; set; }
    }
 
    public class CourseStatusModel
    {
        public int Id { get; set; }
        public string Description { get; set; }
    }
}

Now we need to add Database context class which will be responsible to communicate with our database, so add new class and name it “RegistrationDbContext” then paste the code snippet below:

using Microsoft.Data.Entity;
using System;
using Microsoft.Data.Entity.Metadata;

namespace Registration_MVC6WebApi.Models
{
    public class RegistrationDbContext :DbContext
    {
        public DbSet<Course> Courses { get; set; }

        protected override void OnConfiguring(DbContextOptions options)
        {
            options.UseSqlServer(Startup.Configuration.Get("Data:DefaultConnection:ConnectionString"));
        }
    }
}

Basically what we’ve implemented here is adding our Courses data model as DbSet so it will represent a database table once we run the migrations, note that there is a new method named “OnConfiguration” where we can override it so we’ll be able to specify the data provider which needs to work with our DB context.

In our case we’ll use SQL Server, the constructor for “UseSqlServer” extension method accepts a parameter of type connection string, so we’ll read it from our “config.json” file by specifying the key “Data:DefaultConnection:ConnectionString” for the “Configuration” object we’ve created earlier in Startup class.

Note: This is not the optimal way to set the connection string, there are MVC6 examples out there using this way, but for a reason it is not working with me, so I followed my way.

Lastly we need to add the interface “IRegistrationRepo” and the implementation for this interface “RegistrationRepo”, so add two new files under “Models” folder named “IRegistrationRepo” and “RegistrationRepo” and paste the two code snippets below:

using System;
using System.Collections;
using System.Collections.Generic;
 
namespace Registration_MVC6WebApi.Models
{
    public interface IRegistrationRepo
    {
        IEnumerable<Course> GetCourses();
        Course GetCourse(int courseId);
        Course AddCourse(Course course);
        bool DeleteCourse(int courseId);
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
 
 
namespace Registration_MVC6WebApi.Models
{
    public class RegistrationRepo : IRegistrationRepo
    {
        private readonly RegistrationDbContext _db;
 
        public RegistrationRepo(RegistrationDbContext db)
        {
            _db = db;
        }
        public Course AddCourse(Course course)
        {
            _db.Courses.Add(course);
 
            if (_db.SaveChanges() > 0)
            {
                return course;
            }
            return null;
 
        }
 
        public bool DeleteCourse(int courseId)
        {
            var course = _db.Courses.FirstOrDefault(c => c.Id == courseId);
            if (course != null)
            {
                _db.Courses.Remove(course);
                return _db.SaveChanges() > 0;
            }
            return false;
        }
 
        public Course GetCourse(int courseId)
        {
            return _db.Courses.FirstOrDefault(c => c.Id == courseId);
        }
 
        public IEnumerable<Course> GetCourses()
        {
            return _db.Courses.AsEnumerable();
        }
    }
}

The implementation here is fairly simple, what worth noting here is how we’ve passed “RegistrationDbContext” as parameter for our “RegistrationRepo” constructor so we’ve implemented Constructor Injection, this will not work if we didn’t configure this earlier in our “Startup” class.

Installing KVM (K Version Manager)

After we’ve added our Database context and our domain data models, we can use migrations to create the database, with previous version of ASP.NET we’ve used NuGet package manager for these type of tasks, but with ASP.NET 5 we can use command prompt using various K* commands.

Now to install KVM for the first time you have to do the following steps:

  1. Open a command prompt with Run as administrator.
    2. Run the following command:
@powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/aspnet/Home/master/kvminstall.ps1'))"
  1. The script installs KVM for the current user.
    4. Exit the command prompt window and start another as an administrator (you need to start a new command prompt to get the updated path environment).
    5. Upgrade KVM with the following command:
KVM upgrade

Initializing and applying migrations for our database

Now our command prompt is ready to understand K commands and Entity Framework commands, first step to do is to change the directory to the project directory. The project directory contains the “project.json” file as the image below:

image_4

So in the command prompt we need to run the 2 following commands:

k ef migration add initial
k ef migration apply

Basically the first command will add migration file with the name format (<date>_<migration name>) so we’ll end up having file named “201411172303154_initial.cs” under folder named “Migrations” in our project. This auto generated file contains the code needed to to add our Courses table to our database, the newly generated files will show up under your project as the image below:

image_5

The second command will apply those migrations and create the database for us based on the connection string we’ve specified earlier in file “config.json”.

Note: the “ef” command comes from the settings that we’ve specified earlier in file “project.json” under section “commands”.

Adding GET methods for Courses Controller

The controller is a class which is responsible to handle HTTP requests, with ASP.NET 5 our Web API controller will inherit from “Controller” class not anymore from “ApiController”, so add new folder named “Controllers” then add new controller named “CoursesController” and paste the code below:

using Microsoft.AspNet.Mvc;
using Registration_MVC6WebApi.Models;
using System;
using System.Collections.Generic;
 
namespace Registration_MVC6WebApi.Controllers
{
    [Route("api/[controller]")]
    public class CoursesController : Controller
    {
        private IRegistrationRepo _registrationRepo;
 
        public CoursesController(IRegistrationRepo registrationRepo)
        {
            _registrationRepo = registrationRepo;
        }
 
        [HttpGet]
        public IEnumerable<Course> GetAllCourses()
        {
            return _registrationRepo.GetCourses();
        }
 
        [HttpGet("{courseId:int}", Name = "GetCourseById")]
        public IActionResult GetCourseById(int courseId)
        {
            var course = _registrationRepo.GetCourse(courseId);
            if (course == null)
            {
                return HttpNotFound();
            }
 
            return new ObjectResult(course);
        }
 
    }
}

Adding POST and DELETE methods for Courses Controller

Now we want to implement another two HTTP methods which allow us to add new Course or delete existing one, so open file “CoursesController” and paste the code below:

[HttpPost]
public IActionResult AddCourse([FromBody] Course course)
{
	if (!ModelState.IsValid)
	{
		Context.Response.StatusCode = 400;
		return new ObjectResult(new CourseStatusModel { Id = 1 , Description= "Course model is invalid" });
	}
	else
	{
	   var addedCourse =  _registrationRepo.AddCourse(course);
 
		if (addedCourse != null)
		{
			string url = Url.RouteUrl("GetCourseById", new { courseId = course.Id }, Request.Scheme, Request.Host.ToUriComponent());
 
			Context.Response.StatusCode = 201;
			Context.Response.Headers["Location"] = url;
			return new ObjectResult(addedCourse);
		}
		else
		{
			Context.Response.StatusCode = 400;
			return new ObjectResult(new CourseStatusModel { Id = 2, Description = "Failed to save course" });
		}
	   
	}
}
[crp]