Setting up Asp.net Core application with CRUD operations for beginners

Setting up Asp.net Core application, MVC, WebAPI, CRUD Operations for beginners


Category: ASP.NET Core Tags: ASP.NET Core 2, MVC, WebApi

Asp.net Core Application Code Files

    Asp.net core 1.0 was released in 2016 aimed to remove windows dependency from asp.net applications. Since market was going towards open-source frameworks, Microsoft decided to release Asp.net Core which runtime can be run on other platforms like Linux, Mac and windows.

Since hosting web applications on windows makes .net applications expensive, so many companies decided not to move development in .net. Now it is very easy to run your .net applications on other platforms and most importantly on Linux which is a free and open-source.

In this article, we will aim the audience who wants to start their journey with Asp.net Core, we will create an Asp.net Core application from scratch and perform simple CRUD operations and cover basic modules of Asp.net Core. In next article, I will show you how to host this Asp.net Core application on Linux platform. 

Create an empty Asp.net Core project

    I have Visual Studio 2017 installed on my machine. You may need to install Asp.net Core 2.2 on machine, you may download it from here. Click on File->New->Project and below window appears:

New Project Asp.net Core in Visual Studio 2017
Fig 1: New Project Asp.net Core in Visual Studio 2017

 

Choose Asp.net Core Web Application, give project name and hit enter. New window will appear like:

Asp.net Core Empty Project in Visual Studio 2017
Fig 2: Asp.net Core Empty Project in Visual Studio 2017

 

Select Empty and uncheck all checkbox since I don’t want additional Nuget/frameworks to be referenced. Click OK and you project is created. Below files will be created in Solution Explorer:

 

Asp.net Core Project Default Files
Fig 3: Asp.net Core Project Default Files

Setting up Application’s Configuration, Hosting Url’s and Startup Support

appSettings.json

    We will host out application on URL http://localhost:5000 so Let’s create one entry in appSettings.json. appSettings.json is similar to web config file in standard asp.net application. We have here JSON file instead of XML but we can configure XML file as well. So after adding a URL your appSettings.json will look like:

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*",
  "AppConfig": {
    "Url": "http://localhost:5000"
  }
}

We have added URL in AppConfig wrapper.

Program.cs

    Program.cs is a class file contains Main method which is starting point of the application. Whenever we start or restart the application this method gets executed and sets up host and hosting related configurations.

Kestrel: Kestrel is a web server like IIS which is able to host an Asp.net Core application. Asp.net Core application can not be hosted directly on web servers like Apache so in Linux environment kestrel runs behind Apache or Nginx and request can be routed to kestrel. So we will modify Main method of Program.cs code as below:

public static void Main(string[] args)
{
    //using kkestrel and iis both
    CreateWebHostBuilder(args).UseKestrel().UseIIS().UseUrls(new string[] { "http://localhost:5000" }).Build().Run();
}

UseKestrel enables hosting in Linux platform and UseIIS enables hosting in windows. UseUrls can be used to define on which URL and port application will be served.

WebHost and DefaultBuilder: WebHost is a class of a host and CreateWebHostBuilder method to initialize Host with default host settings. It uses a Startup class to configure app level services, routes, environment etc.

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>();

Startup.cs

    Startup is used to configure some important services like MVC, Dependency Injection, Routes as well Exception handling, setting up request pipeline and many more.

ConfigreServices Method: This method is used to configure some services like MVC, logging, DI etc. We will configure MVC and one entity Student.cs (A custom class provides data of students with some access methods) to be used as dependency injection. ConfigureServices method will look like:

public void ConfigureServices(IServiceCollection services)
{
    //to use mvc
    services.AddMvc();
    //enabling dependency injection
    services.AddSingleton<Models.StudentData>();
}

AddSingleton is used to create only one instance of StudentData class at startup of application and should not be created in each request. Let’s create a folder “Models” in root directory and create a class file StudentData.cs. Implementation of this class is given below:

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

namespace CoreAppSample.Models
{
    public class StudentData
    {
        public List<Student> Students { get; private set; }

        public StudentData()
        {
            Students = new List<Student>();
            Students.Add(new Student() { Id = Guid.NewGuid(), Name = "Alex", FathersName = "Steve", Age = 10 });
            Students.Add(new Student() { Id = Guid.NewGuid(), Name = "Bran", FathersName = "Mark", Age = 12 });
            Students.Add(new Student() { Id = Guid.NewGuid(), Name = "Jon", FathersName = "Dean", Age = 9 });
            Students.Add(new Student() { Id = Guid.NewGuid(), Name = "Linda", FathersName = "Bran", Age = 11 });
            Students.Add(new Student() { Id = Guid.NewGuid(), Name = "Rachel", FathersName = "Jack", Age = 15 });
        }

        public Models.Student GetStudent(Guid id)
        {
            Models.Student student = Students.Where(x => x.Id == id).First();
            return student;
        }

        public bool Add(Models.Student student)
        {
            Students.Add(student);
            return true;
        }

        public bool Update(Models.Student student)
        {
            Models.Student std = Students.Where(x => x.Id == student.Id).First();
            std.Name = student.Name;
            std.FathersName = student.FathersName;
            std.Age = student.Age;
            return true;
        }

        public bool Delete(Guid id)
        {
            Students.Remove(Students.Where(x => x.Id == id).First());
            return true;
        }
    }
}

Configure Method: This method is used to configure routes and request pipeline. We are not using any authentication here but using request pipeline we can authenticate each request. We will only configure routing in below method. Change configure method to:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseMvc(routes =>
    {
        routes.MapRoute("default", "{controller=Student}/{action=Index}/{id?}");
    });
}

Above default controller and action is set to Student and Index respectively. We will implement this controller in upcoming section.

Asp.net Core WebAPI

    Asp.net Core WebAPI is similar to Standard Web API and used to create restful services. Here I will create services to get, add, edit and delete student data. We will create Get, Post, Put and Delete methods to perform CRUD operations.

Create folder “Controllers” and add new API controller StudentServiceController. Implementation of StudentServiceController.cs is given below:

using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;

namespace CoreAppSample.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class StudentServiceController : ControllerBase
    {
        Models.StudentData _students;

        public StudentServiceController(Models.StudentData student)
        {
            _students = student;
        }
        /// <summary>
        /// Get all student data
        /// </summary>
        /// <returns></returns>
        public List<Models.Student> Get()
        {
            return _students.Students;
        }

        /// <summary>
        /// Get student by id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet("{id}")]
        public Models.Student Get(Guid id)
        {
            return _students.GetStudent(id);
        }

        /// <summary>
        /// Create a new student
        /// </summary>
        /// <param name="student"></param>
        /// <returns></returns>
        [HttpPost]
        public bool Post(Models.Student student)
        {
            return _students.Add(student);
        }

        /// <summary>
        /// Edit an existing student
        /// </summary>
        /// <param name="student"></param>
        /// <returns></returns>
        [HttpPut]
        public bool Put(Models.Student student)
        {
            return _students.Update(student);
        }

        /// <summary>
        /// Delete a student
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpDelete("{id}")]
        public bool Delete(Guid id)
        {
            return _students.Delete(id);
        }
    }
}

Above we can see we are using dependency injection which we configured in Startup class. API controller is inherited from ControllerBase class which can not return a view. And the ControllerBase is further extended to Controller class which should be implemented for MVC controller and can return Views. Actually There’s no much difference in MVC controller and API controller in Asp.net Core since base class of both is ControllerBase.

Asp.net Core MVC

    Now let’s create MVC controller named StudentController and all the methods required for CRUD  and from these methods we will call WebAPI services. Below is the implementation of controller:

using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;

namespace CoreAppSample.Controllers
{
    public class StudentController : Controller
    {

        IConfiguration _configuration;
        public StudentController(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        public IActionResult Index()
        {
            System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
            client.BaseAddress = new Uri(_configuration.GetValue<string>("AppConfig:Url"));
            var result = client.GetStringAsync("/api/StudentService");
            List<Models.Student> students = JsonConvert.DeserializeObject<List<Models.Student>>(result.Result);

            return View(students);
        }

        [HttpGet]
        public IActionResult Add()
        {
            return View();
        }

        [HttpPost]
        public IActionResult Add(Guid id, [Bind("Name,FathersName,Age")]Models.Student student)
        {
            student.Id = Guid.NewGuid();
            System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
            client.BaseAddress = new Uri(_configuration.GetValue<string>("AppConfig:Url"));
            System.Net.Http.ObjectContent content = new System.Net.Http.ObjectContent(typeof(Models.Student), student, new System.Net.Http.Formatting.JsonMediaTypeFormatter());
            var result = client.PostAsync("/api/StudentService/", content).Result;

            return RedirectToAction("Index");
        }

        public IActionResult Edit(Guid id)
        {
            System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
            client.BaseAddress = new Uri(_configuration.GetValue<string>("AppConfig:Url"));
            var result = client.GetStringAsync("/api/StudentService/" + id);
            Models.Student student = JsonConvert.DeserializeObject<Models.Student>(result.Result);

            return View(student);
        }

        [HttpPost]
        public IActionResult Edit(Guid id, [Bind("Id,Name,FathersName,Age")]Models.Student student)
        {
            System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
            client.BaseAddress = new Uri(_configuration.GetValue<string>("AppConfig:Url"));
            System.Net.Http.ObjectContent content = new System.Net.Http.ObjectContent(typeof(Models.Student), student, new System.Net.Http.Formatting.JsonMediaTypeFormatter());
            var result = client.PutAsync("/api/StudentService/", content).Result;

            return RedirectToAction("Index");
        }

        public IActionResult Delete(Guid id)
        {
            System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
            client.BaseAddress = new Uri(_configuration.GetValue<string>("AppConfig:Url"));
            var result = client.DeleteAsync("/api/StudentService/" + id).Result;

            return RedirectToAction("Index");
        }
    }
}

We can see we are taking base url from appSettings.json file, GetValue method returns value of a key. We are making call to WebAPI using HttpClient. Now let’s create a folder "Views" and "Student" inside, right click on it and click Add->View give name of view same as action name, select template and model. For adding a new student we will create view like image below:

Adding Asp.net Core View in Visual Studio 2017
Fig 4: Adding Asp.net Core View in Visual Studio 2017

 

Now replace code of the view as given below:

@model CoreAppSample.Models.Student
@addTagHelper "*, Microsoft.AspNetCore.Mvc.TagHelpers"
@{
    ViewData["Title"] = "Add";
}

<h1>Add</h1>

<h4>Student</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Add">
            <div class="form-group">
                <label asp-for="Name" class="control-label"></label>
                <input asp-for="Name" class="form-control" />
            </div>
            <div class="form-group">
                <label asp-for="FathersName" class="control-label"></label>
                <input asp-for="FathersName" class="form-control" />
            </div>
            <div class="form-group">
                <label asp-for="Age" class="control-label"></label>
                <input asp-for="Age" class="form-control" />
            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-action="Index">Back to List</a>
</div>

Now create view for Index (student list) and replace code as below:

@model List<CoreAppSample.Models.Student>

@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<div>
    <h4>Students</h4>
    @Html.ActionLink("Create New", "Add", "Student")
    <hr />
    <table>
        @foreach (CoreAppSample.Models.Student student in Model)
        {
            <tr>
                <td><b>@Html.DisplayNameFor(x => student.Name)</b></td>
                <td>@Html.DisplayTextFor(x => student.Name)</td>
            </tr>
            <tr>
                <td><b>@Html.DisplayNameFor(x => student.FathersName)</b></td>
                <td>@Html.DisplayTextFor(x => student.FathersName)</td>
            </tr>
            <tr>
                <td><b>@Html.DisplayNameFor(x => student.Age)</b></td>
                <td>@Html.DisplayTextFor(x => student.Age)</td>
            </tr>
            <tr>
                <td>@Html.ActionLink("Edit", "Edit", new { id = student.Id })</td>
                <td>@Html.ActionLink("Delete", "Delete", new { id = student.Id })</td>
            </tr>
            <tr>
                <td>&nbsp;</td>
                <td>&nbsp;</td>
            </tr>
        }
    </table>
</div>

Same for Edit:

@model CoreAppSample.Models.Student
@addTagHelper "*, Microsoft.AspNetCore.Mvc.TagHelpers"
@{
    ViewData["Title"] = "Edit";
}

<h1>Edit</h1>

<h4>Student</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form  asp-action="Edit">
            <div class="form-group">
                <input type="hidden" asp-for="Id" class="form-control" />
            </div>
            <div class="form-group">
                <label asp-for="Name" class="control-label"></label>
                <input asp-for="Name" class="form-control" />
            </div>
            <div class="form-group">
                <label asp-for="FathersName" class="control-label"></label>
                <input asp-for="FathersName" class="form-control" />
            </div>
            <div class="form-group">
                <label asp-for="Age" class="control-label"></label>
                <input asp-for="Age" class="form-control" />
            </div>
            <div class="form-group">
                <input type="submit" value="Save" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-action="Index">Back to List</a>
</div>

You can see we are using addTagHelper to render html using helpers which binds the properties to html controls. You will find most of the things similar to standard MVC application.

Running and Debugging the code

    To run and debug we can simply click on IISExpress and debug it. But to use same port and URL we need to change settings of debug config. Open solution explorer, right click on project and go to properties. In debug section select IISExpress and change URL to http://localhost:5000.

Changing Host URL in Visual Studio 2017
Fig 5: Changing Host URL in Visual Studio 2017

 

Now you can simply debug you application. Using IIS Express or can setup on IIS and attach debugger to process "w3wp".

Running on Kestrel: To run and debug with Kestrel, open commend prompt, locate your project folder and give command “dotnet run”. This command will build and run the application.

Running Asp.net Core Application
Fig 6: Running Asp.net Core Application


You can see above, application is stared to listen on specified URL. You can go to Visual Studio and attach to process “dotnet.exe” to debug the code. Open browser and hit http://localhost:5000 you will see students data.


Like 0 People
Last modified on 28 April 2019
Nikhil Joshi

Nikhil Joshi
Ceo & Founder at Dotnetlovers
Atricles: 133
Questions: 9
Given Best Solutions: 9 *

Comments:

No Comments Yet

You are not loggedin, please login or signup to add comments:

Existing User

Login via:

New User



x