Click here to Skip to main content
13,740,369 members
Click here to Skip to main content
Add your own
alternative version

Stats

28.9K views
2.4K downloads
40 bookmarked
Posted 6 Feb 2018
Licenced CPOL

Securing ASP.NET CORE Web API using Custom API Key based Authentication

, 6 Feb 2018
Rate this:
Please Sign up or sign in to vote.
In this article, we are going to learn how to create a secure Web API in ASP.NET Core MVC.

Credit: Icons made by Smashicons from www.flaticon.com is licensed by CC 3.0 BY

In the fast-growing era of Web technology everything is changing too fast. With ASP.NET there was time when we used to use web service (the .asmx ones), which was SOAP-based, which we can just use for consuming data from other applications, which did have that much of security in it. Most developers would take Username and Password Parameter as input and then they would allow to access web service.

As time passes, Microsoft came up with WCF which was secured but too complex to use.

Further, Microsoft came up with something new called as Web API which we can use by creating ASP.NET MVC application or directly ASP.NET Web API application which was lighter and easy to use.

But moving further, Microsoft introduces ASP.NET Core which is lighter than all its previous versions.

But when we say we are securing and webapi in ASP.NET WEB API we use Delegate handler for validating API request.

As we jump into ASP.NET Core there are no more handler and modules, we are introduced to something new called as Middleware, which we are going to write to validating API request.

In this article, we are going to learn that extra part, the process to create an ASP.NET Core WEB API application in which a developer can log in to application and subscribe his own services, then generate API keys, see his own documentation of API how to consume API and finally he will get his own analytics on how many requests he sends in a month. And if request sent count is greater than the user has subscribed then he will get the response "exceeds request length".

Process

  • Register Developer
  • Login
  • Choose Service with Max request (1000 request, 5000 requests)
  • Get API key
  • API Documents
  • Use API key to Access service

Prerequisite

Visual Studio 2017 with ASP.NET CORE 2.0

SQL Server 2008 and above

Database parts

In this part, we have created the database with name "MoviesDB" and it has 7 tables which we are going to use in the application.

Tables Details

  1. APIManagerTB: - Stores all services and API Keys.
  2. MoviesTB: - Stores all movies details.
  3. MusicTB: - Stores all music details.
  4. RegisterUser: - Stores all Registered User details.
  5. ServicesTB: - Stores all Service details
  6. LoggerTB: - Stores all request log of API
  7. HitsTB: - Stores all Request values (1000 request, 2000 request)

Creating WEB API Application

Open New Visual Studio 2017 IDE.

After opening IDE, next, we are going to create ASP.NET MVC Core project. For doing that, just click File - New - Project.

After choosing a project, a new dialog will pop up with the name "New Project". In that, we are going to choose Visual C# Project Templates-.NET Core- ASP.NET Core Web Application. Then, we are going to name the project as "MoviesAPIStore".

After naming the project, click on OK button to create the project. A new dialog will pop up for choosing templates for creating "Web Application (Model View Controller)" click on the OK button to create the project.

After configuring the project next, we are going to see project structure.

Using Entity Framework Core Code first approach to connecting application to Database

The first step we are going to add a connection string in appsettings.json file.

The second step we are going to create Models according to MoviesDB database.

The third step we are going to add a MoviesContext folder and inside that folder, we are going to add DatabaseContext class which will inherit Dbcontext class.

Code snippet of DatabaseContext class

using Microsoft.EntityFrameworkCore;
using MoviesAPIStore.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace MoviesAPIStore.MoviesContext
{
    public class DatabaseContext : DbContext
    {
        public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options)
        {
          
        }
        public DbSet<RegisterUser> RegisterUser { get; set; }
        public DbSet<ServicesTB> ServicesTB { get; set; }
        public DbSet<HitsTB> HitsTB { get; set; }
        public DbSet<APIManagerTB> APIManagerTB { get; set; }
        public DbSet<MoviesTB> MoviesTB { get; set; }
        public DbSet<MusicTB> MusicTB { get; set; }
        public DbSet<LoggerTB> LoggerTB { get; set; }

    }
}

Adding Repository Folder to Application

In this part, we are going to add Repository Folder to project in this folder we are going to keep all project interfaces and a concrete class.

Register User

Credit: Man free Icons made by monkik from www.flaticon.com is licensed by CC 3.0 BY
  1. RegisterUser Model
  2. Adding IRegisterUser Interface
  3. Adding RegisterUserConcrete class
  4. Adding Controller
  5. Adding View.
  6. Setting Dependency injection in startup class for injecting dependence of RegisterUserConcrete class.

Let’s start with RegisterUser Model

1. RegisterUser Model

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;

namespace MoviesAPIStore.Models
{
    [Table("RegisterUser")]
    public class RegisterUser
    {
        [Key]
        public long UserID { get; set; }

        [Required(ErrorMessage = "Required Username")]
        [StringLength(30, MinimumLength = 2, ErrorMessage = "Username Must be Minimum 2 Charaters")]
        public string Username { get; set; }

        [DataType(DataType.Password)]
        [Required(ErrorMessage = "Required Password")]
        [MaxLength(30, ErrorMessage = "Password cannot be Greater than 30 Charaters")]
        [StringLength(31, MinimumLength = 7, ErrorMessage = "Password Must be Minimum 7 Charaters")]
        public string Password { get; set; }
        public DateTime CreateDate { get; set; }

        [Required(ErrorMessage = "Required EmailID")]
        [RegularExpression(@"[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}", ErrorMessage = "Please enter Valid Email ID")]
        public string EmailID { get; set; }
    }
}

After completing with adding RegisterUser model next we are going to add IRegisterUser interface and in this interface, we are going to declare all methods which we require for Registering users.

2. IRegisterUser interface

In this part, we are going to add IRegisterUser interface to repository folder and this interface contains four methods in it.

  • Add: for creating a new User which takes RegisterUser Model as input
  • ValidateRegisteredUser: for validating username and password entered by the user.
  • ValidateUsername: for validating Username entered by user (does similar Username already exists in database)
  • GetLoggedUserID: Get logged in UserID by username and password entered by the user.

Code snippet

using MoviesAPIStore.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace MoviesAPIStore.Repository
{
    public interface IRegisterUser
    {
        void Add(RegisterUser registeruser);
        bool ValidateRegisteredUser(RegisterUser registeruser);
        bool ValidateUsername(RegisterUser registeruser);
        long GetLoggedUserID(RegisterUser registeruser);
    }
}

3. RegisterUserConcrete class

The RegisterUserConcrete class will inherit IRegisterUser interface and implements all methods in it.

Code snippet of RegisterUserConcrete class

using MoviesAPIStore.Models;
using MoviesAPIStore.MoviesContext;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace MoviesAPIStore.Repository
{
    public class RegisterUserConcrete : IRegisterUser
    {
        private DatabaseContext _context;

        public RegisterUserConcrete(DatabaseContext context)
        {
            _context = context;
        }

        public void Add(RegisterUser registeruser)
        {
            try
            {
                registeruser.UserID = 0;
                _context.RegisterUser.Add(registeruser);
                _context.SaveChanges();
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        public long GetLoggedUserID(RegisterUser registeruser)
        {
            var usercount = (from User in _context.RegisterUser
                             where User.Username == registeruser.Username && User.Password == registeruser.Password
                             select User.UserID).FirstOrDefault();

            return usercount;
        }

        public bool ValidateRegisteredUser(RegisterUser registeruser)
        {
            var usercount = (from User in _context.RegisterUser
                             where User.Username == registeruser.Username && User.Password == registeruser.Password
                             select User).Count();
            if (usercount > 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public bool ValidateUsername(RegisterUser registeruser)
        {
            var usercount = (from User in _context.RegisterUser
                             where User.Username == registeruser.Username
                             select User).Count();
            if (usercount > 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}

After adding RegisterUserConcrete class next we are going to have a look at dependency injection.

Understanding Dependency injection

In this process, we are going to use constructor injection for injecting dependency.

We are going to inject DbContext as a dependency to RegisterUserConcrete class to access specific entity (RegisterUser).

Snapshot while injecting Dbcontext

After having look at DatabaseContext injection you might wonder how I am injecting dependency, right? The ASP.NET Core MVC comes with inbuilt dependency injection framework, just you need to configure it, it is located in startup.cs under ConfigureServices method.

Configuring dependency

In the above snapshot you can see that we have configured DatabaseContext dependency whenever you use DatabaseContext class, DbContext instance will be injected there.

And another thing you can see that we have added services.Configure method this is used for getting connection string as dependency and we are getting connection string as "Configuration.GetSection("ConnectionStrings")" this connection string we are going to use with dapper ORM.

The last dependency which we have added is AddTransient. In this we need to configure an interface and concrete class.

Code snippet

services.AddTransient<Interface, ConcreteClass>();

Whenever we are going to use interface at that time the concrete class instance will be injected thereby dependency injection framework.

Now we have configured dependency of IRegisterUser interface and RegisterUserConcrete Concrete class.

As we move ahead we are going register more dependency in ConfigureServices method in the same way as we need for IRegisterUser interface and RegisterUserConcrete Concrete class.

What is Concrete class?

The class which inherits interface is called Concrete class.

Reference: https://stackoverflow.com/questions/38138100/what-is-the-difference-between-services-addtransient-service-addscope-and-servi

In .NET's dependency injection there are three major lifetimes:

Singleton which creates a single instance throughout the application. It creates the instance for the first time and reuses the same object in the all calls.

Scoped lifetime services are created once per request within the scope. It is equivalent to Singleton in the current scope. For example, in MVC it creates one instance per each HTTP request but uses the same instance in the other calls within the same web request.

Transient lifetime services are created each time they are requested. This lifetime works best for lightweight, stateless services.

After completing with understand dependency injection configuration let’s add RegisterUser Controller.

4. Adding RegisterUser Controller

For adding controller just right click on controller folder then choose -> Add -> inside that, choose to Add New item. A new dialog will popup of Add New item inside that choose "MVC Controller Class" and Name your controller as "RegisterUserController" and click on Add button to create a RegisterUser controller.

After creating controller next, we are going to use constructor injection for inject dependency.

For that we are going to add a constructor which will take IRegister interface as input and at runtime dependency injection will inject dependency of IRegister interface which is RegisterUserConcrete.

Code snippet of RegisterUserController

using System;
using Microsoft.AspNetCore.Mvc;
using MoviesAPIStore.Repository;
using MoviesAPIStore.Models;
using MoviesAPIStore.AES256Encryption;

// For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace MoviesAPIStore.Controllers
{
    public class RegisterUserController : Controller
    {
        IRegisterUser _repository;
        public RegisterUserController(IRegisterUser repository)
        {
            _repository = repository;
        }

        [HttpGet]
        // GET: RegisterUser/Create
        public ActionResult Create()
        {
            return View(new RegisterUser());
        }

        // POST: RegisterUser/Create
        [HttpPost]
        public ActionResult Create(RegisterUser RegisterUser)
        {
            try
            {
                if (!ModelState.IsValid)
                {
                    return View("Create", RegisterUser);
                }

                // Validating Username 
                if (_repository.ValidateUsername(RegisterUser))
                {
                    ModelState.AddModelError("", "User is Already Registered");
                    return View("Create", RegisterUser);
                }
                RegisterUser.CreateDate = DateTime.Now;

                // Encrypting Password with AES 256 Algorithm
                RegisterUser.Password = EncryptionLibrary.EncryptText(RegisterUser.Password);

                // Saving User Details in Database
                _repository.Add(RegisterUser);
                TempData["UserMessage"] = "User Registered Successfully";
                ModelState.Clear();
                return View("Create", new RegisterUser());
            }
            catch
            {
                return View();
            }
        }
    }
}

In RegisterUser Controller, we have added two Action Methods of creating one for handling [HttpGet] request and other for handling [HttpPost] request. In [HttpPost] request we are going to first Validate Is Username already exists or not if not then we are going to Create User, next we are also taking Password as input which we cannot store in database as clear text we need to store it in encrypted format for doing that we are going to Use AES 256 algorithm.

5. RegisterUser View

Note: After Registering a User Below are details which get stored in RegisterUser Table.

6. RegisterUser Table

After completing with Registration part next we are going create a Login page.

Login

In this part, we are going to create a login controller with two action methods. One to handle get request and other for handling post request and the same way we are going to add a Login view.

In controller part of LoginController, we are going to use dependency injection to inject dependency of RegisterUserConcrete such that we can access method inside of it.

We are going to use "ValidateRegisteredUser" method to validate User credentials, if the user is valid then we are going push request to the dashboard page, else we are going show error on the Login page.

Code snippet of LoginController

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using MoviesAPIStore.AES256Encryption;
using MoviesAPIStore.Models;
using MoviesAPIStore.Repository;
using System;

namespace MoviesAPIStore.Controllers
{

    public class LoginController : Controller
    {
        IRegisterUser _IRegisterUser;
        public LoginController(IRegisterUser IRegisterUser)
        {
            _IRegisterUser = IRegisterUser;
        }

        public ActionResult Login()
        {
            return View(new RegisterUser());
        }

        [HttpPost]
        public ActionResult Login(RegisterUser RegisterUser)
        {
            try
            {

                if (string.IsNullOrEmpty(RegisterUser.Username) && (string.IsNullOrEmpty(RegisterUser.Password)))
                {
                    ModelState.AddModelError("", "Enter Username and Password");
                }
                else if (string.IsNullOrEmpty(RegisterUser.Username))
                {
                    ModelState.AddModelError("", "Enter Username");
                }
                else if (string.IsNullOrEmpty(RegisterUser.Password))
                {
                    ModelState.AddModelError("", "Enter Password");
                }
                else
                {

                   RegisterUser.Password = EncryptionLibrary.EncryptText(RegisterUser.Password);

                    if (_IRegisterUser.ValidateRegisteredUser(RegisterUser))
                    {
                        var UserID = _IRegisterUser.GetLoggedUserID(RegisterUser);
                        HttpContext.Session.SetString("UserID", Convert.ToString(UserID));

                        return RedirectToAction("Dashboard", "Dashboard");
                    }
                    else
                    {
                        ModelState.AddModelError("", "User is Already Registered");
                        return View("Login", RegisterUser);
                    }
                }

                return View("Login", RegisterUser);
            }
            catch(Exception)
            {
                return View();
            }
        }

        public ActionResult Logout()
        {
            HttpContext.Session.Clear();
            return RedirectToAction("Login", "Login");
        }
    }

}

After login, we are going to see a simple dashboard pages with charts.

Dashboard page

This is a simple dashboard page I am going to explain in detail in the upcoming steps.

After having a look at the Dashboard page you can see that we have Generate API KEY Menu the, next thing we are going to do is Create a generate API Key Page where users can generate Key for API.

Generating API Keys

Credit: Icons made by Round icons from www.flaticon.com is licensed by CC 3.0 BY.

Adding ApplicationKeys Controller

In ApplicationKeysController we are going to add two action methods with name GenerateKeys. One for handling get and other for handling post request.

And on GenerateKeys page we are going to add two dropdown lists, one for displaying service and the other for displaying Max request count.

After the user chooses these dropdowns then the user is going click on Create API Key button to generate API Key to access this APIs.

Let’s have a look at GenerateKeysVM Model.

Code snippet of GenerateKeysVM Model

using MoviesAPIStore.Filters;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace MoviesAPIStore.Models
{
    public class GenerateKeysVM
    {
        [Required(ErrorMessage ="Choose Service")]
        [ServiceValidate]
        public int? ServiceID { get; set; }
        [HitValidate]
        [Required(ErrorMessage = "Choose Max Request")]
        public int? HitsID { get; set; }

        public List<HitsTB> ListHits { get; set; }
        public List<ServicesTB> ListServices { get; set; }

        public string APIKey { get; set; }
    }
}

After adding GenerateKeysVM model next we are going to add ServicesStore interface and Concrete class.

IServicesStore interface

In IServicesStore interface we have added two methods GetServiceList and GetServiceListforDashboard.

Code snippet of IServicesStore interface

using MoviesAPIStore.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace MoviesAPIStore.Repository
{
    public interface IServicesStore
    {
        List<ServicesTB> GetServiceList();
        List<ServicesTB> GetServiceListforDashboard();
    }
}

After adding IServicesStore interface next, we are going to add a ServicesStore Concrete class.

Code snippet of ServicesStoreConcrete class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MoviesAPIStore.Models;
using MoviesAPIStore.MoviesContext;

namespace MoviesAPIStore.Repository
{
    public class ServicesStoreConcrete : IServicesStore
    {
        private DatabaseContext _context;

        public ServicesStoreConcrete(DatabaseContext context)
        {
            _context = context;
        }

        public List<ServicesTB> GetServiceList()
        {
            try
            {
                var ServiceList = (from services in _context.ServicesTB
                                   select services).ToList();

                ServiceList.Insert(0, new ServicesTB { ServiceName = "---Choose Service---", ServiceID = -1 });
                return ServiceList;
            }
            catch (Exception)
            {

                throw;
            }
        }

        public List<ServicesTB> GetServiceListforDashboard()
        {
            try
            {
                var ServiceList = (from services in _context.ServicesTB
                                   select services).ToList();

                return ServiceList;
            }
            catch (Exception)
            {

                throw;
            }
        }
    }

}

After completing with adding IServicesStore interface and ServicesStoreConcrete class next we are going to add Ihits interface.

Adding Ihits interface

Ihits interface contains methods used for displaying HitsList (Max Request Dropdown) and used for displaying charts on the dashboard.

Code snippet of Ihits interface

using MoviesAPIStore.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace MoviesAPIStore.Repository
{
    public interface IHits
    {
        List<HitsTB> GetHitsList();
        List<string> GetChartsMoviesreport();
        List<string> GetChartsMusicreport();
    }
}

Adding HitsConcrete Class

In this part, we have implemented all methods which are declared IHits interface. In this concrete class for some methods, we have used Dapper ORM for getting data from the database. And you can see constructor of this class we are taking two inputs, one of DatabaseContext and IOptions<ConnectionStrings>, the DatabaseContext will get an instance of DbContext and IOptions<ConnectionStrings> will get an instance of configuration (Connection string).

Code snippet of HitsConcrete Class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MoviesAPIStore.Models;
using MoviesAPIStore.MoviesContext;
using Dapper;
using System.Data.SqlClient;
using Microsoft.Extensions.Options;

namespace MoviesAPIStore.Repository
{
    public class HitsConcrete : IHits
    {
        private DatabaseContext _context;
        private ConnectionStrings _connectionstrings;

        public HitsConcrete(DatabaseContext context, IOptions<ConnectionStrings> connectionstrings)
        {
            _context = context;
            _connectionstrings = connectionstrings.Value;
        }

        public List<HitsTB> GetHitsList()
        {
            try
            {
                var hitsList = (from services in _context.HitsTB select services).ToList();
                hitsList.Insert(0, new HitsTB { HitsDisplay = "---Choose Max Request---", HitsID = -1 });
                return hitsList;
            }
            catch (Exception)
            {

                throw;
            }
        }

        public List<string> GetChartsMoviesreport()
        {
            try
            {
                using (SqlConnection con = new SqlConnection(Convert.ToString(_connectionstrings.DatabaseConnection)))
                {
                    var parameter = new DynamicParameters();
                    return con.Query<string>("Usp_GetChartsMoviesreport", null, null, false,0, System.Data.CommandType.StoredProcedure).ToList();
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        public List<string> GetChartsMusicreport()
        {
            try
            {
                using (SqlConnection con = new SqlConnection(Convert.ToString(_connectionstrings.DatabaseConnection)))
                {
                    var parameter = new DynamicParameters();
                    return con.Query<string>("Usp_GetChartsMusicreport", null, null, false, 0, System.Data.CommandType.StoredProcedure).ToList();
                }
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
}

After adding IHits interface and HitsConcrete class next we are going to add IAPIManager interface.

Adding IAPIManager interface

In this interface, we are going to add method which is required for generating, saving and validating API Key along with that we have added two methods Deactivate and Reactivate Service which can be used by the user to activate and Deactivate his own services.

Code snippet of IAPIManager interface

using MoviesAPIStore.Models;

namespace MoviesAPIStore.Repository
{
    public interface IAPIManager
    {
        int isApikeyAlreadyGenerated(int? ServiceID, int? UserID);

        int GenerateandSaveToken(APIManagerTB APIManagerTB);

        APIManagerVM GetApiDetailsbyServiceIDandUserID(int? ServiceID, int? UserID);

        int DeactivateService(int? ServiceID, int? UserID);

        int ReactivateService(int? ServiceID, int? UserID);
    }
}

After adding IAPIManager interface next, we are going to add APIManagerConcrete class which will implement IAPIManager.

Code snippet of APIManagerConcrete

using Dapper;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using MoviesAPIStore.Models;
using MoviesAPIStore.MoviesContext;
using System;
using System.Data.SqlClient;
using System.Linq;

namespace MoviesAPIStore.Repository
{
    public class APIManagerConcrete : IAPIManager
    {
        private DatabaseContext _context;
        private ConnectionStrings _connectionstrings;
        public APIManagerConcrete(DatabaseContext context, IOptions<ConnectionStrings> connectionstrings)
        {
            _context = context;
            _connectionstrings = connectionstrings.Value;
        }

        public int isApikeyAlreadyGenerated(int? ServiceID, int? UserID)
        {
            try
            {
                var keyCount = (from apimanager in _context.APIManagerTB
                                where apimanager.ServiceID == ServiceID &&
                                      apimanager.UserID == UserID
                                select apimanager).Count();

                return keyCount;
            }
            catch (Exception)
            {
                throw;
            }
        }

        public int GenerateandSaveToken(APIManagerTB APIManagerTB)
        {
            try
            {
                _context.APIManagerTB.Add(APIManagerTB);
                return _context.SaveChanges();
            }
            catch (Exception)
            {
                throw;
            }
        }

        public APIManagerVM GetApiDetailsbyServiceIDandUserID(int? ServiceID, int? UserID)
        {
            try
            {

                using (SqlConnection con = new SqlConnection(Convert.ToString(_connectionstrings.DatabaseConnection)))
                {
                    var parameter = new DynamicParameters();
                    parameter.Add("@ServiceID", ServiceID);
                    parameter.Add("@UserID", UserID);
                    var apimanagervm = con.Query<APIManagerVM>("Usp_GetApiDetailsbyServiceIDandUserID", parameter, null, false, 0, System.Data.CommandType.StoredProcedure).SingleOrDefault();

                    if(apimanagervm ==null)
                    {
                        return new APIManagerVM();
                    }
                    else
                    {
                        return apimanagervm;
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        public int DeactivateService(int? ServiceID, int? UserID)
        {
            try
            {
                using (SqlConnection con = new SqlConnection(Convert.ToString(_connectionstrings.DatabaseConnection)))
                {
                    var parameter = new DynamicParameters();
                    parameter.Add("@ServiceID", ServiceID);
                    parameter.Add("@UserID", UserID);
                    return con.Execute("Usp_DeactivateService_update", parameter, null, 0, System.Data.CommandType.StoredProcedure);
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        public int ReactivateService(int? ServiceID, int? UserID)
        {
            try
            {
                using (SqlConnection con = new SqlConnection(Convert.ToString(_connectionstrings.DatabaseConnection)))
                {
                    var parameter = new DynamicParameters();
                    parameter.Add("@ServiceID", ServiceID);
                    parameter.Add("@UserID", UserID);
                    return con.Execute("Usp_ReactivateService_update", parameter, null, 0, System.Data.CommandType.StoredProcedure);
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

       
    }
}

Snapshot of Repository

After completing with adding all interface and concrete class which are required for generating, validating and saving API key next we are going to add ApplicationKeys Controller.

Adding ApplicationKeysController

In this controller, we are going to add two action methods with the name "GenerateKeys" one for handling [HttpGet] and other for handling [HttpPost] request.

In [HttpGet] GenerateKeys method we are going to assign values of ListServices and ListHits to GenerateKeysVM View model and send that model to view the binding dropdown list.

In [HttpPost] GenerateKeys method we are going get values for Service and Hits which the user has chosen. Next we are going validate Service and Hits values against database and check is this service already subscribe if yes then we are going to show the alert message "API Key for Chosen Service is Already Generated". If service not already subscribe then we are going to generate unique APIKey for that service.

Code snippet of ApplicationKeysController

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using MoviesAPIStore.Repository;
using MoviesAPIStore.Models;
using MoviesAPIStore.AES256Encryption;
using Microsoft.AspNetCore.Http;
using MoviesAPIStore.Filters;
using Newtonsoft.Json;

// For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace MoviesAPIStore.Controllers
{
    [ValidateUserSession]
    public class ApplicationKeysController : Controller
    {
        IServicesStore _IServicesStore;
        IHits _IHits;
        IAPIManager _IAPIManager;
        public ApplicationKeysController(IServicesStore IServicesStore, IHits IHits, IAPIManager IAPIManager)
        {
            _IServicesStore = IServicesStore;
            _IHits = IHits;
            _IAPIManager = IAPIManager;
        }

        [HttpGet]
        // GET: /<controller>/
        public IActionResult GenerateKeys()
        {
            try
            {

                GenerateKeysVM generateKeysVM = new GenerateKeysVM();
                generateKeysVM.ListServices = _IServicesStore.GetServiceList();
                generateKeysVM.ListHits = _IHits.GetHitsList();
                return View(generateKeysVM);
            }
            catch (Exception)
            {
                throw;
            }
        }

        [HttpPost]
        public IActionResult GenerateKeys(GenerateKeysVM generateKeysVM)
        {

            if (ModelState.IsValid)
            {
                var userID = Convert.ToInt32(HttpContext.Session.GetString("UserID"));

                if (_IAPIManager.isApikeyAlreadyGenerated(generateKeysVM.ServiceID, userID) > 0)
                {
                    ModelState.AddModelError("", "Api Key for Choosen Service is Already Generated");
                    generateKeysVM.ListServices = _IServicesStore.GetServiceList();
                    generateKeysVM.ListHits = _IHits.GetHitsList();
                    return View(generateKeysVM);
                }

                generateKeysVM.ListServices = _IServicesStore.GetServiceList();
                generateKeysVM.ListHits = _IHits.GetHitsList();

                if (GenerateKey(generateKeysVM) == 1)
                {
                    TempData["APIKeyGeneratedMessage"] = "Done";
                }
                else
                {
                    TempData["APIKeyGeneratedMessage"] = "Failed";
                }

                return View(generateKeysVM);
            }

            generateKeysVM.ListServices = _IServicesStore.GetServiceList();
            generateKeysVM.ListHits = _IHits.GetHitsList();


            return View(generateKeysVM);
        }

        [NonAction]
        public int GenerateKey(GenerateKeysVM GenerateKeysVM)
        {
            try
            {
                APIManagerTB aPIManagerTB = new APIManagerTB()
                {
                    APIKey = EncryptionLibrary.KeyGenerator.GetUniqueKey(),
                    HitsID = GenerateKeysVM.HitsID,
                    CreatedOn = DateTime.Now,
                    ServiceID = GenerateKeysVM.ServiceID,
                    UserID = Convert.ToInt32(HttpContext.Session.GetString("UserID")),
                    Status = "A"
                };

                return _IAPIManager.GenerateandSaveToken(aPIManagerTB);
            }
            catch (Exception)
            {
                throw;
            }
        }


        public IActionResult DeactivateService(string ServiceID)
        {
            try
            {
                var result = _IAPIManager.DeactivateService(Convert.ToInt32(ServiceID), Convert.ToInt32(HttpContext.Session.GetString("UserID")));
                return Json(data: result);
            }
            catch (Exception)
            {
                throw;
            }
        }

        public IActionResult ReActivateService(string ServiceID)
        {
            try
            {
                var result = _IAPIManager.ReactivateService(Convert.ToInt32(ServiceID), Convert.ToInt32(HttpContext.Session.GetString("UserID")));
                return Json(data: result);
            }
            catch (Exception)
            {
                throw;
            }
        }

    }
}

After understanding work of ApplicationKeysController next we see how we are generating unique APIKey and inserting that key into the database.

Code snippet of GenerateKey

[NonAction]
public int GenerateKey(GenerateKeysVM GenerateKeysVM)
{
    try
    {
        APIManagerTB aPIManagerTB = new APIManagerTB()
        {
            APIKey = EncryptionLibrary.KeyGenerator.GetUniqueKey(),
            HitsID = GenerateKeysVM.HitsID,
            CreatedOn = DateTime.Now,
            ServiceID = GenerateKeysVM.ServiceID,
            UserID = Convert.ToInt32(HttpContext.Session.GetString("UserID")),
            Status = "A"
        };

        return _IAPIManager.GenerateandSaveToken(aPIManagerTB);
    }
    catch (Exception)
    {
        throw;
    }
}

Next, we are going to add GenerateKeys View and add two dropdown lists and a button on it.

Snapshot for GenerateKey

Next for generating a key we are going to choose Service and Max Request and click on "Create API Key" button to generate the key.

APIManager Table view after Generating API Key

After generating Key next, we are going Add a ServicesStore Controller which will display all services on it after clicking on that service you can see your API Key for that service.

Adding ServicesStore Controller

Credit: Man free Icons made by monkik from www.flaticon.com is licensed by CC 3.0 BY

In this controller, we have two action methods. Both are [HttpGet] methods, one for displaying service (Service) on view and another for showing details (Details) of that service.

Code snippet of ServicesStore Controller

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using MoviesAPIStore.Repository;
using MoviesAPIStore.Filters;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using MoviesAPIStore.Models;

// For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace MoviesAPIStore.Controllers
{
    [ValidateUserSession]
    public class ServicesStoreController : Controller
    {
        IServicesStore _IServicesStore;
        IAPIManager _iAPIManager;

        public ServicesStoreController(IServicesStore IServicesStore, IAPIManager iAPIManager)
        {
            _IServicesStore = IServicesStore;
            _iAPIManager = iAPIManager;
        }

        // GET: /<controller>/
        public IActionResult Service()
        {
            return View(_IServicesStore.GetServiceListforDashboard());
        }

        public IActionResult Details(string ServiceID, string ServiceName)
        {
            try
            {
                var userID = Convert.ToInt32(HttpContext.Session.GetString("UserID"));
                var apiDetails = _iAPIManager.GetApiDetailsbyServiceIDandUserID(Convert.ToInt32(ServiceID), userID);
                return View(apiDetails);
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
}

View of Service.cshtml

@model List<MoviesAPIStore.Models.ServicesTB>
@{
    Layout = "~/Views/Shared/_LayoutDashboard.cshtml";
}
<h2>Services</h2>
<div class="row">

    @foreach (var service in Model)
    {
        <div class="col-sm-4">
            <div class="card">
                <div class="content">
                    <div class="row">
                        <div class="col-xs-5">
                            <div class="icon-big icon-info text-center">
                                <i class="ti-settings-alt"></i>
                            </div>
                        </div>
                        <div class="col-xs-7">
                            <div class="numbers">
                                @service.ServiceName API
                            </div>
                        </div>
                    </div>
                    <div class="footer">
                        <hr />
                        <div class="stats">
                            <i class="ti-reload"></i> <a target="_blank" href="/ServicesStore/Details/@service.ServiceID/@service.ServiceName">Service Link</a>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    }
</div>

Snapshot of Service View

Now clicking on Movies API service link you can see details view of service with API Key for it.

Here you have an option to deactivate service and reactivate service also by click on Deactivate button.

Snapshot of after Deactivating service

Snapshot of after Re-activating service

After completing with adding services controller and activating and deactivating services Next we are going to create Movies API.

Adding Movies API

Credit for icon: Icons made by Freepik from www.flaticon.com is licensed by CC 3.0 BY

In this part, before adding Web API Controller we are going to add Interface and concrete class to get data from the database.

Adding IMovies interface

The IMovie’s interface contains a single method inside it which is GetMoviesStore which will return a list of Movies.

Code snippet of IMovies interface

using MoviesAPIStore.Models;
using System.Collections.Generic;

namespace MoviesAPIStore.Repository
{
    public interface IMovies
    {
        List<MoviesTB> GetMoviesStore();
    }
}

Adding MoviesConcrete Class

The Movies concrete class implement IMovie’s interface.

Code snippet of MoviesConcrete Class

using MoviesAPIStore.Models;
using MoviesAPIStore.MoviesContext;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace MoviesAPIStore.Repository
{
    public class MoviesConcrete : IMovies
    {
        private DatabaseContext _context;
        public MoviesConcrete(DatabaseContext context)
        {
            _context = context;
        }

        // GET: api/LatestMovies
        public List<MoviesTB> GetMoviesStore()
        {
            try
            {
                var listofMovies = _context.MoviesTB.ToList();
                return listofMovies;
            }
            catch (System.Exception)
            {
                throw;
            }
        }

    }
}

Adding Movies Controller

In this part, we are going to add Web API Controller with name "MoviesAPIController" and this controller will return List of Movies. We have only implement POST method.

Code snippet

using Microsoft.AspNetCore.Mvc;
using MoviesAPIStore.Models;
using MoviesAPIStore.Repository;
using System.Collections.Generic;

namespace MoviesAPIStore.Controllers
{
    [Route("api/[controller]")]
    public class MoviesAPIController : Controller
    {
        IMovies _IMovies;
        public MoviesAPIController(IMovies IMovies)
        {
            _IMovies = IMovies;
        }

        // POST api/values
        [HttpPost]
        public List<MoviesTB> Post([FromQuery]string key)
        {
            return _IMovies.GetMoviesStore();
        }
    }
}

In the same way, we are going to add Music API.

After completing with adding Movies and Music API next we are going to added Swagger for API documentation.

Adding Swagger to Application for API Documentation

What Is Swagger?

Swagger allows you to describe the structure of your APIs so that machines can read them.

The ability of APIs to describe their own structure is the root of all awesomeness in Swagger. Why is it so great? Well, by reading your API’s structure, we can automatically build beautiful and interactive API documentation. We can also automatically generate client libraries for your API in many languages and explore other possibilities like automated testing.

Referenced: https://swagger.io/docs/specification/2-0/what-is-swagger/

For adding swagger to project just right click on Movies API store project and from the list choose "Manage NuGet packages" a new window of NuGet will pop up inside that choose to browse tab and search "Swashbuckle.AspNetCore" and click on install button to install swagger.

After adding Swagger, we need to add some middleware of swagger to startup.cs class to make it work.

Below is a snapshot of startup class in which we registered and added swagger middleware.

Now let’s save the application and run to see API documentation.

To access swagger just after localhost port, enter "/swagger".

Swagger UI

Wow, we have just configured it not written any code for design and documentation.

API Documentation for Movies API

API Documentation for Music API

Now we have complete with see documentation of both APIs next let’s validate API request by create Middleware.

Authenticating API Request Mechanism

Credit: Icons made by Eucalyp from www.flaticon.com is licensed by CC 3.0 BY

In this process we have provided API key to user (client) now while we are creating API authentication mechanism we are going to validate every request come from client, and every request must contain API key which we have provided such that we can validate API key against database and check that user is authorized to access this service. If API key is valid then the user will get a response from API if the request is not valid then the user will get error message what he is missing in the request.

And one new functionally we have added in this process is we can activate and deactivate our service if user deactivate service and then he tries to access service then he will get an error message "Service is Deactivated".

Next point is we have max request limit in this API application, if user has subscribed 1000 request and he tries to access API more than 1000 request he will get an error message "Request Limit Exceeded"

And last scenario use might have subscribed two services and he sends Movies API key to Music API request and vice versa then he will get an error message "Invalid User Key".

And if the request is valid then we send movies collection as a response.

Till now we have completed adding API and its documentation, now let’s have right the main process of this application is middleware to validate the request.

Let’s start with adding interface with name IValidateRequest and declaring methods in it.

Adding IValidateRequest Interface

namespace MoviesAPIStore.Repository
{
    public interface IValidateRequest
    {
        bool ValidateKeys(string Key);

        bool IsValidServiceRequest(string Key, string ServiceName);

        bool ValidateIsServiceActive(string Key);

        bool CalculateCountofRequest(string Key);
    }
}

We have declared four methods in the IValidateRequest interface.

  1. ValidateKeys

    In this method, we are going to take API key as input and check this key exists in the database.

  2. IsValidServiceRequest

    In this method are going to check API Key is sent to valid API. For that, we are taking key and Service Name (API Name) as input.

    For example, for Music API developer is not send Movies API key.

  3. ValidateIsServiceActive

    In this method, we are taking API key as input and check against a database that this service is Active or deactivate.

  4. CalculateCountofRequest

    In this method, we are taking API key as input and check request count against this API key.

    For example, if the user had subscribed for 1000 request service and if he exceeds the limit.

Adding ValidateRequest Concrete Class

In this part, we are going to add Concrete class with name ValidateRequestConcrete which is going to inherit IValidateRequest interface and implement all methods in it.

Code snippet of ValidateRequest Concrete class

using Microsoft.EntityFrameworkCore;
using MoviesAPIStore.MoviesContext;
using System;
using System.Collections.Generic;
using System.Linq;

namespace MoviesAPIStore.Repository
{
    public class ValidateRequestConcrete : IValidateRequest
    {
        private DatabaseContext _context;

        public ValidateRequestConcrete(DatabaseContext context)
        {
            _context = context;
        }

        public bool ValidateKeys(string Key)
        {
            try
            {
                var result = (from apimanagertb in _context.APIManagerTB
                              where EF.Functions.Like(apimanagertb.APIKey, "%" + Key + "%")
                              select apimanagertb).Count();

                if (result > 0)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        public bool IsValidServiceRequest(string Key ,string ServiceName)
        {
            try
            {
                var serviceID = (from apimanagertb in _context.APIManagerTB
                              where EF.Functions.Like(apimanagertb.APIKey, "%" + Key + "%")
                              select apimanagertb.ServiceID).FirstOrDefault();

                var serviceName = (from servicestb in _context.ServicesTB
                                 where servicestb.ServiceID == serviceID
                                   select servicestb.APIName).FirstOrDefault();

                if (string.Equals(ServiceName, serviceName,StringComparison.InvariantCultureIgnoreCase))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        public bool ValidateIsServiceActive(string Key)
        {
            try
            {
                var result = (from apimanagertb in _context.APIManagerTB
                              where EF.Functions.Like(apimanagertb.APIKey, "%" + Key + "%") && apimanagertb.Status == "A"
                              select apimanagertb).Count();

                if (result > 0)
                {
                    return true;
                }
                else
                {
                    return false;
                }

            }
            catch (Exception)
            {
                throw;
            }
        }

        public bool CalculateCountofRequest(string Key)
        {
            try
            {

                var totalRequestCount = (from apimanagertb in _context.APIManagerTB
                              join hittb in _context.HitsTB on apimanagertb.HitsID equals hittb.HitsID
                              where apimanagertb.APIKey == Key
                              select hittb.Hits).FirstOrDefault();

                var totalCurrentRequestCount = (from loggertb in _context.LoggerTB
                              where loggertb.APIKey == Key
                              select loggertb).Count();

                if (totalCurrentRequestCount >= totalRequestCount)
                {
                    return false;
                }
                else
                {
                    return true;
                }

            }
            catch (Exception)
            {
                throw;
            }
        }
    }
}

Snapshot after Adding Interface IValidateRequest and ValidateRequestConcrete

Adding Middleware to validate API request

Before starting this process let’s understand why middleware if we create a simple application in ASP.NET MVC in that for validating request API we use DelegatingHandler, now in ASP.NET core it has been replaced with middleware.

What is middleware?

Middleware is software that's assembled into an application pipeline to handle requests and responses.

Referenced: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?tabs=aspnetcore2x

Let’s start with adding Middleware.

Note: adding middleware just right click on Middlewares folder then choose -> Add ->New Item a new dialog will pop with name Add New Item, inside that choose "ASP.NET Core" -> "Web" then in List of templates you will find "Middleware Class" just choose it.

For adding middleware, we are going to create a Middlewares folder in the application, inside that we are going to add middleware with name "ApiKeyValidatorsMiddleware".

Code Snippet of ApiKeyValidatorsMiddleware

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using MoviesAPIStore.Models;
using MoviesAPIStore.Repository;
using System;
using System.Threading.Tasks;

namespace MoviesAPIStore.Middlewares
{
    // You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project
    public class ApiKeyValidatorsMiddleware
    {
        private readonly RequestDelegate _next;
        IValidateRequest _IValidateRequest { get; set; }
        IRequestLogger _IRequestLogger { get; set; }
        public ApiKeyValidatorsMiddleware(RequestDelegate next, IValidateRequest ivalidaterequest, IRequestLogger irequestlogger)
        {
            _next = next;
            _IValidateRequest = ivalidaterequest;
            _IRequestLogger = irequestlogger;
        }

        public async Task Invoke(HttpContext httpContext)
        {
            try
            {
                var remoteIpAddress = httpContext.Connection.RemoteIpAddress;

                if (httpContext.Request.Path.StartsWithSegments("/api"))
                {
                    var queryString = httpContext.Request.Query;
                    StringValues keyvalue;
                    queryString.TryGetValue("key", out keyvalue);

                    if (httpContext.Request.Method != "POST")
                    {
                        httpContext.Response.StatusCode = 405; //Method Not Allowed               
                        await httpContext.Response.WriteAsync("Method Not Allowed");
                        return;
                    }

                    if (keyvalue.Count == 0)
                    {
                        httpContext.Response.StatusCode = 400; //Bad Request                
                        await httpContext.Response.WriteAsync("API Key is missing");
                        return;
                    }
                    else
                    {
                        string[] serviceName = httpContext.Request.Path.Value.Split('/');
          


                        if(!_IValidateRequest.IsValidServiceRequest(keyvalue, serviceName[2]))
                        {
                            httpContext.Response.StatusCode = 401; //UnAuthorized
                            await httpContext.Response.WriteAsync("Invalid User Key or Request");
                            return;
                        }
                        else if (!_IValidateRequest.ValidateKeys(keyvalue))
                        {
                            httpContext.Response.StatusCode = 401; //UnAuthorized
                            await httpContext.Response.WriteAsync("Invalid User Key");
                            return;
                        }
                        else if (!_IValidateRequest.ValidateIsServiceActive(keyvalue))
                        {
                            httpContext.Response.StatusCode = 406; //NotAcceptable
                            await httpContext.Response.WriteAsync("Service is Deactived");
                            return;
                        }
                        else if (!_IValidateRequest.CalculateCountofRequest(keyvalue))
                        {
                            httpContext.Response.StatusCode = 406; //NotAcceptable
                            await httpContext.Response.WriteAsync("Request Limit Exceeded");
                            return;
                        }
                        else
                        {
                            string[] apiName = httpContext.Request.Path.Value.Split('/');

                            var loggertb = new LoggerTB()
                            {
                                LoggerID = 0,
                                ContentType = Convert.ToString(httpContext.Request.ContentType),
                                APIKey = keyvalue,
                                CreatedDate = DateTime.Now,
                                Host = httpContext.Request.Host.Value,
                                IsHttps = httpContext.Request.IsHttps ? "Yes" : "No",
                                Path = httpContext.Request.Path,
                                Method = httpContext.Request.Method,
                                Protocol = httpContext.Request.Protocol,
                                QueryString = httpContext.Request.QueryString.Value,
                                Scheme = httpContext.Request.Scheme,
                                RemoteIpAddress = Convert.ToString(httpContext.Connection.RemoteIpAddress),
                                LoggerAPI = apiName[2],

                            };

                            _IRequestLogger.InsertLoggingData(loggertb);

                        }
                    }


                }
                await _next.Invoke(httpContext);
            }
            catch (Exception)
            {
                throw;
            }
        }
    }

    // Extension method used to add the middleware to the HTTP request pipeline.
    public static class MiddlewareExtensions
    {
        public static IApplicationBuilder UseMiddleware(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<ApiKeyValidatorsMiddleware>();
        }
    }
}

Let’s understand code of middleware

In this middleware first, we are injecting two dependencies

  1. IValidateRequest
  2. IRequestLogger

IValidateRequest interface contains all API validation methods in it.

IRequestLogger interface contains a method for logging all API request.

Next, after adding newly middleware, you will see Invoke method in which we are going to write entire validation process.

  1. The first step we are validating is we are only going to validate API request.

  2. In a second step, we are going to only allow post request for all API. If it is another request, then we are going send an error message.

  3. In the third step, we are going check does query string ("Key") exists in request URI.

  4. In the fourth step, we are going to check the key user sent in request and API he is accessing are valid. For example, For Music API developer is not send Movies API key.

  5. In the fifth step, we are going to check the key user sent is valid or not.

  6. In the sixth step, we are going to check API Key against a database that this service is Active or deactivate.

  7. In the Seventh step, we are going to check API request count against this API key if it exceeds then we are going to send an error response to the user.

Finally, if request past all barriers means the request is valid.

Registering Middleware in startup.cs

Now let’s register this middleware in a startup.cs class such as every API request can be validated.

Now we completed with Adding and registering "ApiKeyValidators" Middleware. Now let’s run the application and check how middleware works.

Accessing Latest Movies API Controller

For accessing Movies API, we need API key which we have generated.

Snapshot of Movies API KEY

Now we are going to use POSTMAN APP to access Movies API.

Setting up POST Request Parameters

For downloading Postman APP Click on below URL:

https://www.getpostman.com/postman

Setting Parameters for API.

URL: http://localhost:50911/api/MoviesAPI?key=XtSREijsrZYkt9S

API Name: MoviesAPI

API Key: XtSREijsrZYkt9S

Request Type: POST

After sending valid key and request we got response.

Response after sending Valid API Request

Send Invalid Request Type

We have sent Get request to Movies API, it shows "Method Not Allowed" because in middleware we have only allowed POST request for all APIs.

Send Invalid Key

We have sent invalid API key in this request to test what response we get.

Deactivate Movies Service and Send Request

We have deactivated Movies API Service let’s send a request and test what response we get.

The response we get is proper "Service is Deactivated".

Sending Request More then we subscribed

We have subscribed 1000 request and we have sent complete 1000 request, I am trying to send the request again then it shows error message "Request Limit Exceeded".

The table where we have stored a log of all API request.

Snapshot of LoggerTB table

Now we have completed with security part let’s have a look at the Dashboard.

Final Project Structure

This is a final project structure of the application.

In this part we can see a folder for storing AES256Encryption algorithm, filters folder contains a filter for validating user session. Middleware folder for storing all middleware of application. And repository for storing interface and concrete classes.

Note: I have keep repository folder in main application because this is small demo application in the large application you need to move it to separate class library, the same way you need to do for models also.

Dashboard

On this dashboard, you can see your Request graph for API. For Movies API we have sent 1000 Request that’s why it has to peek at the chart.

These charts are shown on data which is logged in every request.

These charts are CHARTIST.JS.

Snapshot of Dashboard

Tools Used in this Project

  1. cDesign Template: Paper Dashboard by Creative Tim
  2. Swagger
  3. Dapper ORM
  4. chartist.js Charts
  5. Icons from https://www.flaticon.com/
  6. AES256 Encryption

Conclusion

In this article, we have learned a complete cycle of API development in ASP.NET Core WEB API. We started with registering User then we have generated API Key further we have Created API along with that we have provided feature to activate and deactivate service, then we came to the main process of validating API request, and finally we have done logging of each request such that a developer or normal user know how many times user has requested an API.

Thank you, I hope you liked my article.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

saineshwar bageri
Software Developer (Senior)
India India
I am Microsoft MVP | C# Corner MVP working on.Net Web Technology
[ASP.NET MVC,.Net Core,ASP.NET CORE, C#, Sqlserver, MYSQL, MongoDB, Windows]

Microsoft MVP Profile Link
https://mvp.microsoft.com/en-us/PublicProfile/5003160?fullName=Saineshwar%20%20Bageri

Prize.

First Prize: Best Web Dev Article of August 2016 with 10 Points to Secure Your ASP.NET MVC Applications.

Second Prize: Best Web Dev Article of April 2017 with Securing ASP.NET Web API using Custom Token Based Authentication

Second Prize:
Best Web Dev Article of February 2018 with Securing ASP.NET CORE Web API using Custom API Key based Authentication




You may also be interested in...

Pro
Pro

Comments and Discussions

 
QuestionCannot run sample project Pin
Member 1384455629-May-18 10:52
memberMember 1384455629-May-18 10:52 
QuestionBroken link for readme file Pin
Mou_kol5-Mar-18 21:58
memberMou_kol5-Mar-18 21:58 
AnswerRe: Broken link for readme file Pin
saineshwar bageri6-Mar-18 17:00
membersaineshwar bageri6-Mar-18 17:00 
GeneralMy vote of 5 Pin
Mou_kol5-Mar-18 21:56
memberMou_kol5-Mar-18 21:56 
Questioni have problems charts Pin
lonely999912-Feb-18 3:26
memberlonely999912-Feb-18 3:26 
AnswerRe: i have problems charts Pin
saineshwar bageri12-Feb-18 5:17
membersaineshwar bageri12-Feb-18 5:17 
GeneralRe: i have problems charts Pin
lonely999912-Feb-18 5:41
memberlonely999912-Feb-18 5:41 
GeneralRe: i have problems charts Pin
saineshwar bageri12-Feb-18 18:58
membersaineshwar bageri12-Feb-18 18:58 
GeneralRe: i have problems charts Pin
lonely999913-Feb-18 4:15
memberlonely999913-Feb-18 4:15 
Question[My vote of 2] Middleware hidden in article with too many distractions and bad practices Pin
Marc Lewandowski10-Feb-18 2:32
professionalMarc Lewandowski10-Feb-18 2:32 
AnswerRe: [My vote of 2] Middleware hidden in article with too many distractions and bad practices Pin
saineshwar bageri10-Feb-18 21:52
membersaineshwar bageri10-Feb-18 21:52 
PraiseRe: [My vote of 2] Middleware hidden in article with too many distractions and bad practices Pin
Virshu8-Apr-18 9:27
memberVirshu8-Apr-18 9:27 
GeneralRe: [My vote of 2] Middleware hidden in article with too many distractions and bad practices Pin
Kelvin Wu14-Aug-18 22:44
memberKelvin Wu14-Aug-18 22:44 
GeneralMy vote of 5 Pin
Suvendu Shekhar Giri7-Feb-18 0:16
professionalSuvendu Shekhar Giri7-Feb-18 0:16 
GeneralRe: My vote of 5 Pin
saineshwar bageri7-Feb-18 2:51
membersaineshwar bageri7-Feb-18 2:51 
PraiseGood Article Pin
madhan20086-Feb-18 22:29
membermadhan20086-Feb-18 22:29 
GeneralRe: Good Article Pin
saineshwar bageri6-Feb-18 23:34
membersaineshwar bageri6-Feb-18 23:34 
GeneralMy vote of 5 Pin
6-Feb-18 22:06
member6-Feb-18 22:06 
QuestionArticle is too long Pin
Klaus Luedenscheidt6-Feb-18 19:06
memberKlaus Luedenscheidt6-Feb-18 19:06 
AnswerRe: Article is too long Pin
saineshwar bageri6-Feb-18 20:43
membersaineshwar bageri6-Feb-18 20:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web06-2016 | 2.8.180920.1 | Last Updated 6 Feb 2018
Article Copyright 2018 by saineshwar bageri
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid