Performing CRUD Operations With ASP.NET MVC Core And Entity Framework Core

Introduction

ASP.NET Core is a significant redesign of ASP.NET. It is an open source, cross-platform framework to develop Cloud based applications like web applications, IoT applications, and mobile back-end applications. We can develop and run the ASP.NET Core application on multiple (cross) platforms, such as Windows, Mac OS, and Linux. Entity Framework Core is a lightweight and extensible version of Entity Framework. It is based on ORM (Object-Relational Mapper) which enables us to work with databases using .NET objects.

In this article, we will learn how to perform CRUD (Create, Read, Update and Delete) operations in ASP.net Core MVC, using Entity Framework Core. Here, I have used the "Code First" approach for developing Entity model and as a development tool, I am using "Visual Studio Code". Here, I am doing manual database migration.

To use Entity Framework and MVC, we need to include certain references in project.json file. The following highlighted references need to be included.

{
  "version": "1.0.0-*",
  "buildOptions": {
    "preserveCompilationContext": true,
    "debugType": "portable",
    "emitEntryPoint": true
  },
  "dependencies": {},
  "frameworks": {
    "netcoreapp1.0": {
      "dependencies": {
        "Microsoft.NETCore.App": {
          "type": "platform",
          "version": "1.0.1"
        },
        "Microsoft.EntityFrameworkCore.SqlServer": "1.0.0",
        "Microsoft.EntityFrameworkCore.SqlServer.Design": "1.0.0",
        "Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
        "Microsoft.AspNetCore.Mvc": "1.0.0",
        "Microsoft.AspNetCore.Mvc.Formatters.Xml": "1.0.0",
        "Microsoft.Framework.Configuration.Json": "1.0.0-beta7"
      },
      "imports": [
        "dnxcore50",
        "portable-net452+win81"
      ]
    }
  }
}

I have created “TestTables” table in database. It has three columns - Id, Name, and Description. Id is primary key and auto-incremented.

CREATE TABLE [dbo].[TestTables] (
    [Id] INT NOT NULL IDENTITY(1,1),
    [Name] VARCHAR(50) NULL,
    [Description] VARCHAR(50) NULL,
    CONSTRAINT [PK_TestTable] PRIMARY KEY CLUSTERED (
        [Id] ASC
    ) WITH (
        PAD_INDEX = OFF,
        STATISTICS_NORECOMPUTE = OFF,
        IGNORE_DUP_KEY = OFF,
        ALLOW_ROW_LOCKS = ON,
        ALLOW_PAGE_LOCKS = ON
    ) ON [PRIMARY]
) ON [PRIMARY];

The next step is to create Entity model and TestTable entity.

EntityMoidel.cs

using Microsoft.EntityFrameworkCore;

namespace WebApplication
{
    public class EntityModelContext : DbContext
    {
        public DbSet<TestTable> TestTables { get; set; }
    }
}

TestTable.cs

namespace WebApplication
{
    public class TestTable
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
    }
}

Now, I am adding "appsettings.json" file which holds various settings for the application. I have added database connection string in this file.

Appsettings.json

{
  "ConnectionStrings": {
    "DefaultConnection": "Data Source=10.124.130.116;Initial Catalog=TestDB;User ID=sa; Password=Passwd@12"
  },
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  }
}

Startup.cs file is used to register services and injection of modules in HTTP pipeline. It has Startup class which is triggered when application launches the first time.

This is same as Application_Start() event of global.asax file.

In this file, I have registered various services, like MVC, EF etc. Also, configure some global settings, like assigning connection string to dbcontext.

Startup.cs

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Framework.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System.IO;
using Microsoft.EntityFrameworkCore.Infrastructure;

namespace WebApplication
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            var builder = new ConfigurationBuilder(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json");

            var configuration = builder.Build();

            services.AddMvc();
            services.AddEntityFramework()
                .AddDbContext<EntityModelContext>(options =>
                    options.UseSqlServer(configuration["ConnectionStrings:DefaultConnection"]));
        }

        public void Configure(IApplicationBuilder app)
        {
            app.UseMvc();

            app.Run(context =>
            {
                return context.Response.WriteAsync("");
            });
        }
    }
}

Creating Application User Interface

The next step is to create UI. In this step, I have created Controller and various required View. I have “HomeController.cs” file under the Controllers folder and created two Views under the “Views” folder. Following snap is showing the hierarchy of folders and files within our project.

Following is the code snippet for HomeController.

HomeController.cs

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

namespace WebApplication
{
    public class HomeController : Controller
    {
        private EntityModelContext _context = null;

        public HomeController(EntityModelContext context)
        {
            _context = context;
        }

        [Route("home/index")]
        public IActionResult Index()
        {
            List<TestTable> data = _context.TestTables.ToList();
            return View(data);
        }

        [Route("home/edit/{id?}")]
        [HttpGet]
        public IActionResult Edit(int? id)
        {
            TestTable data = new TestTable();
            if (id.HasValue)
            {
                data = _context.TestTables
                    .Where(p => p.Id == id.Value)
                    .FirstOrDefault();
                if (data == null)
                {
                    data = new TestTable();
                }
                return View("Edit", data);
            }
            return View("Edit", data);
        }

        [Route("home/post")]
        [HttpPost]
        public IActionResult Post(TestTable test)
        {
            if (test != null)
            {
                bool isNew = false;
                var data = _context.TestTables
                    .Where(p => p.Id == test.Id)
                    .FirstOrDefault();
                if (data == null)
                {
                    data = new TestTable();
                    isNew = true;
                }
                data.Name = test.Name;
                data.Description = test.Description;
                if (isNew)
                {
                    _context.Add(data);
                }
                _context.SaveChanges();
            }
            return RedirectToAction("Index");
        }

        [Route("home/delete/{id}")]
        [HttpGet]
        public IActionResult Delete(int id)
        {
            TestTable data = _context.Set<TestTable>()
                .FirstOrDefault(c => c.Id == id);
            _context.Entry(data).State = Microsoft.EntityFrameworkCore.EntityState.Deleted;
            _context.SaveChanges();
            return RedirectToAction("Index");
        }
    }
}

Index view (Initial List View)

It is the entry point of the application. Following is the code snippet for index View.

Index.cshtml

@model IEnumerable<WebApplication.TestTable>
@using WebApplication;

<table>
    <thead>
        <tr>
            <th>Id</th>
            <th>Name</th>
            <th>Description</th>
            <th></th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model)
        {
            <tr>
                <td>@item.Id</td>
                <td>@item.Name</td>
                <td>@item.Description</td>
                <td>@Html.ActionLink("Edit", "Edit", new { Id = item.Id })</td>
                <td>@Html.ActionLink("Delete", "Delete", new { Id = item.Id }, new { onclick = "return confirm('Are you sure you want to delete this record?');" })</td>
            </tr>
        }
    </tbody>
</table>
<br />
@Html.ActionLink("Add Item", "Edit", new { Id = 0 })

When we run this application, we might observe the following error. It is related to Entity Framework and tells us that database provider has not been configured.

“No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions<TContext> object in its constructor and passes it to the base constructor for DbContext”.

The solution for this error is hidden in the message itself. This message tells us to add a new constructor to our DbContext, which will accept DbContextOption as parameter.

EntityModelContext.cs

public class EntityModelContext : DbContext
{
    public EntityModelContext(DbContextOptions<EntityModelContext> options) : base(options)
    {
    }

    // Other code or methods
}

Now, I am re-running the application. No such error prompts this time and it is running successfully.

Output

Create add /edit/delete view

Now, I am defining the "Add/Edit" View. The following is the code snippet for "edit.cshtml".

Edit.cshtml

@model WebApplication.TestTable
@using WebApplication;

@using (Html.BeginForm("Post", "Home", FormMethod.Post, new { }))
{
    @Html.ValidationSummary(true)

    <fieldset>
        <legend></legend>
        <div class="editor-label">
            ID
        </div>
        <div class="editor-field">
            @Html.TextBoxFor(model => model.Id, new { @readonly = "readonly" })
        </div>
        <div class="editor-label">
            Name
        </div>
        <div class="editor-field">
            @Html.TextBoxFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>
        <div class="editor-label">
            Description
        </div>
        <div class="editor-field">
            @Html.TextBoxFor(model => model.Description)
            @Html.ValidationMessageFor(model => model.Description)
        </div>

        <p>
            <input type="submit" value="Update" id="btnsave" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Close", "Index")
</div>

Output

At the time of deleting items, the system will ask for conformation. And if the user clicks on “Ok” button, system will delete the record from database.

Delete conformation

Conclusion

This article gave us the insights of CRUD operations in ASP.NET Core MVC, using Entity Framework Core. In the example, I have used simple form post method to perform the CRUD operations.