Building Apps with Polymer and ASP.NET CORE (Part - II)

OK! As I told you in the previous post that I will make APIs using ASP.NET CORE Web API to be able to Add, Update, Edit and Delete todo items on the server side but the good news is ASP.NET CORE documentation already has an article on that. Here is the link,

https://docs.asp.net/en/latest/tutorials/first-web-api.html

Wait a minute! That doesn’t mean I’m not going to do anything in this post. If you went through that article already then you may have noticed that on the server side they are using a ConcurrentDictionary to store the todo items in the memory. Problem is if I stop the project, all my todo items will be wiped out of the memory. So, we need a persistent data storage system. We could have store them in a simple file system but why don’t we store them in a database?

Our database will be local so there is no additional installation of third party software. If you have Visual Studio 2015 installed then you already have SQLSERVER local databse in your machine. We are going to talk with our database using Entity Framework. Entity Framework is a ORM (Object Relational Mapping) tool. Basically it allows you to map a POCO (Plain Old Class Object) to a database table. To be more precise, think of the POCO(In Entity Framework, the POCOs are called entities) as a shadow to a specific database table. Every property defined in the POCO represents a column in that table. To actually make a POCO represent a database table, you have to pass the type of the POCO in a generic class called DbSet<POCO> and give it a name. Like this for example,

public DbSet Todos { get; set; }

This statement will create a database table named Todos with columns named after the properties defined in the Todo class. We can execute queries against this Todos property using C# code. No need to use those old ADO.NET queries like: SELECT, UPDATE, DELETE. There can be multiple DbSets which will represent additional tables in the database. But they must be defined in an Entity Framework database context. More clearly, we must create these DbSets in a class and extend the class from DBContext like this,


public class TodoContext : DbContext
{
    public DbSet<Todo> Todos { get; set; }
}

Let’s do those things I talked about now in our project (If you followed the article on the link I provided earlier, you should have an up and running project by now). Add a new folder in the project and name it Data and create a class under it. I named the class TodoContext since my application is a todo application, or you can choose a name of your like. Code for that class is given below,


using Asp.Net.Core.With.Polymer.Starter.Models;
using Microsoft.EntityFrameworkCore;

namespace Asp.Net.Core.With.Polymer.Starter.Data
{
    public class TodoContext : DbContext
    {
        public TodoContext(DbContextOptions<TodoContext> options) : base(options) {}

        public DbSet<Todo> Todos { get; set; }
    }
}

Remember to add the using statements. In this case DbSet and DbContext is a part of a package called Microsoft.EntityFrameworkCore. To install that package, simply add the package name with the version along with the other packages (under the dependencies node) which are already installed when the project was created,


"Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore": "1.0.0"

Before using the Todos DbSet in our TodoRepository (Repositories are responsible for working with data) we have to configure a database connection for the project. Add a ASP.NET Configuration File in the project. By default it will create a ConnectionStrings node where a connection string is placed in the DefaultConnection node.


{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\MSSQLLocalDB;Database=_CHANGE_ME;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

Just change the database name before you proceed (it is named todo_db on my end). In the Startup.cs we have to configure our DbContext class to use that default connection. So here it is,


public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);

        Configuration = builder.Build();
    }

    public IConfigurationRoot Configuration { get; }
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext < TodoContext > (options = >
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

        services.AddMvc();
        services.AddSingleton< ITodoRepository, TodoRepository> ();

    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseMvc();
    }
}

Here in the constructor, we are building a configuration root which eventually stores the configurations defined in the appsetting.json file as a key-value pair. Then in the ConfigureServices, we get the default connection string by its key. Entity framework can work with a wide range of database systems. Since we are using SqlServer here, so we are configuring it in the option of the AddDbContext<TodoContext> with our connection string.

Let’s move on to the TodoRepository. We will add a private TodoContext variable which we can use to work on the Todos DbSet indside the methods of the repository. Also remove the existing ConcurrentDictionary since we don’t need it anymore. Also in the contructor set the private context variable to the passed in context variable (see code below). The reason of doing this is to have dependency injection in our system. You don’t have to worry about configuring it like we did for the ITodoRepository,


services.AddSingleton<ITodoRepository, TodoRepository>();

It is already configured to inject a new instance of the TodoContext if we defined a parameter of that DbContext in the constructor


services.AddDbContext(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));


Now replace everything in the TodoRepository class with the code given below,


using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Asp.Net.Core.With.Polymer.Starter.Data;
using Asp.Net.Core.With.Polymer.Starter.Models;

namespace Asp.Net.Core.With.Polymer.Starter.Repository
{
    public class TodoRepository : ITodoRepository
    {
        private readonly TodoContext _context;

        public TodoRepository(TodoContext context)
        {
            _context = context;
        }

        public IEnumerable<Todo> GetAll()
        {
            return _context.Todos;
        }

        public void Add(Todo item)
        {
            item.Id = Guid.NewGuid().ToString();
            item.DateAdded = DateTime.Now;
            item.IsDone = false;

            _context.Todos.Add(item);
            _context.SaveChanges();
        }

        public Todo Find(string id)
        {
            Todo todo = _context.Todos.AsNoTracking().FirstOrDefault(s => s.Id == id);
            return todo;
        }

        public Todo Remove(string id)
        {
            Todo todo = _context.Todos.FirstOrDefault(s => s.Id == id);
            _context.Todos.Remove(todo);
            _context.SaveChanges();

            return todo;
        }

        public void Update(Todo item)
        {
            _context.Todos.Update(item);
            _context.SaveChanges();
        }
    }
}

As you can see we are doing basic CRUD on the Todos DbSet with the help of the TodoContext. Nothing more to say here because everything is self-explanatory. But always remember to call the SaveChanges() function on the context when you are doing something on the database table and need to save the changes. Without calling it nothing will be changed. Also notice that when we are saving a todo item, we are adding the current date and time within the DateAdded property and generating a new GuId to set on the Id property. The Id is for the todo to have a unique identity in the database (Primary Key). Also we are setting the IsDone status property of the todo item to false.

Everything looks good! Except for that we didn’t run a migration command on our database. A migration command will create a shadow copy of the current state of the database (tables, schema, indexes, key) in a .cs file. The .cs file name would be the name of the migration with a timestamp added to the front. Run the following command in the package manager window to add a migration named Initial


Add-Migration Initial

If you getting errors, then there is nothing to worry about! Your project is missing some packages like,


Microsoft.EntityFrameworkCore.Tools
Microsoft.EntityFrameworkCore.SqlServer.Design

Here is the final look of the project.json file,


{
  "dependencies": {
    "Microsoft.NETCore.App": {
      "version": "1.0.0",
      "type": "platform"
    },
    "Microsoft.AspNetCore.Mvc": "1.0.0",
    "Microsoft.AspNetCore.Diagnostics": "1.0.0",
    "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
    "Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
    "Microsoft.Extensions.Logging.Console": "1.0.0",
    "Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore": "1.0.0",
    "Microsoft.AspNetCore.StaticFiles": "1.0.0",
    "Microsoft.EntityFrameworkCore.SqlServer": "1.0.0",
    "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0",
    "Microsoft.Extensions.Configuration.Json": "1.0.0",
    "Microsoft.Extensions.Configuration.UserSecrets": "1.0.0",
    "Microsoft.EntityFrameworkCore.SqlServer.Design": {
      "version": "1.0.0",
      "type": "build"
    },
    "Microsoft.EntityFrameworkCore.Tools": {
      "version": "1.0.0-preview2-final",
      "type": "build"
    }
  },

  "tools": {
    "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final",
    "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final"
  },

  "frameworks": {
    "netcoreapp1.0": {
      "imports": [
        "dotnet5.6",
        "portable-net45+win8"
      ]
    }
  },

  "buildOptions": {
    "emitEntryPoint": true,
    "preserveCompilationContext": true
  },

  "runtimeOptions": {
    "configProperties": {
      "System.GC.Server": true
    }
  },

  "publishOptions": {
    "include": [
      "wwwroot",
      "web.config"
    ]
  },

  "scripts": {
    "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
  }
}

After the command is successful, you will have the Initial.cs file with the current timestamp attached to it. Now we need to apply it. So run this command in the package manager window,


update-database

After this is successful, you should have a database in your local database with the name you selected for the database and a new table called Todos like this,

And we are done! Now we can call our APIs from postman(a REST client) and if we add a new todo it will be added directly into our database. Then of course we can update or delete it if we want with the help of other APIs.

Next up, we will see how to make ajax calls to these APIs from Polymer. Till then have fun.