Creating Web API With Repository Pattern And Dependency Injection

Introduction

ASP.NET Web API is a framework, which makes it easy to build HTTP Services, which reaches a broad range of clients, including Browsers and mobile devices. ASP.NET Web API is an ideal platform to build RESTful Applications on .NET Framework.

Here, in this article, we will focus on the things, mentioned below.
  • Layered Architecture of Web API Project.
  • Working with Repository Pattern in Web API Project.
  • Working with Dependency Injection  in Web API.
  • Explaining Entity Framework for Data Access.
Normally, a Web API is nothing but encapsulation of business logic, which is used by different clients to create client side Applications like mobile apps or Web apps.



Now, just create a Web API Project  with the layers of the project, mentioned below.



Here is the complete picture of how these layers appear in the project after hosting it.


Now, we will check each layer one by one in detail, so the first layer is WEB API Layer.

This layer is mainly used to handle the request coming from any client. The Web API layers mainly contain Controller classes. These controller classes are derived from API Controller. In each controller, we have several Action Methods and we are writing our logic.


Now, the second is my IBLL layer. Here, my IBLL layer contains all the interfaces, where all the abstract classes have an abstract method, which will be declared. Thus, the controller will call the IBLL layer, where all my interfaces are defined.

Here, I have created a IProduct.cs interface, where I have declared all the abstract methods to manipulate some operation.
Here, I have declared the abstract class, as shown below.


    1. using System;  
    2. using System.Collections.Generic;  
    3. using System.Linq;  
    4. using System.Text;  
    5. using System.Threading.Tasks;  
    6. using Demo.model;  
    7.   
    8. namespace Demo.IBll  
    9. {  
    10.    public  interface IProduct  
    11.     {  
    12.        bool SaveProducts(ProductDetailsModel pod);  
    13.        List<ProductDetailsModel> searchdetails(string id);  
    14.         List<ProductDetailsModel> showDetails();  
    15.   
    16.     }  
    17. }  
    Here, I have declared three abstract methods, as mentioned above.

    Here is my Model Layer, where all my model classes and properties are declared.



    Here is my ProductDetailsModel.cs.
    1. using System;  
    2. using System.Collections.Generic;  
    3. using System.Linq;  
    4. using System.Text;  
    5. using System.Threading.Tasks;  
    6.   
    7. namespace Demo.model  
    8. {  
    9.     public class ProductDetailsModel  
    10.     {  
    11.         public long slNo { get; set; }  
    12.         public string ProductName { get; set; }  
    13.         public string ProductDetail { get; set; }  
    14.         public int Price { get; set; }  
    15.         public string ProductType { get; set; }  
    16.     }  
    17. }  
    Now, I will declare a Helper Class, which is inherited from the IProduct Interface, as shown below.


    1. using System;  
    2. using System.Collections.Generic;  
    3. using System.Linq;  
    4. using System.Text;  
    5. using System.Threading.Tasks;  
    6. using Demo.IBll;  
    7. using Demo.model;  
    8. using AutoMapper;  
    9. using Demo.Data;  
    10.   
    11. namespace Demo.BL  
    12. {  
    13.     public  class ProductManager : IProduct  
    14.     {  
    15.         DemoEntities2 _dbContext = new DemoEntities2();  
    16.         public bool SaveProducts(ProductDetailsModel pod)  
    17.         {  
    18.             productDetail pd = new productDetail();  
    19.             pd.ProductName = pod.ProductName;  
    20.             pd.ProductDetail1= pod.ProductDetail;  
    21.             pd.Price = pod.Price;  
    22.             pd.Type = pod.ProductType;  
    23.             _dbContext.productDetails.Add(pd);  
    24.             if(_dbContext.SaveChanges()==1)  
    25.             {  
    26.                 return true;  
    27.   
    28.             }  
    29.             else  
    30.             {  
    31.                 return false;  
    32.   
    33.             }  
    34.   
    35.         }  
    36.         public  List<ProductDetailsModel> searchdetails(string type)  
    37.         {  
    38.             
    39.             List<ProductDetailsModel> li = new List<ProductDetailsModel>();  
    40.             var details = _dbContext.productDetails.Where(x => x.Type == type);  
    41.             if(details!=null)  
    42.             {  
    43.                 Parallel.ForEach(details, x =>  
    44.                 {  
    45.                     ProductDetailsModel obj = new ProductDetailsModel();  
    46.                     obj.slNo = x.slNo;  
    47.                     obj.ProductName = x.ProductName;  
    48.                     obj.Price = Convert.ToInt32(x.Price);  
    49.                     li.Add(obj);  
    50.   
    51.                 });  
    52.                 return li;  
    53.             }  
    54.             else  
    55.             {  
    56.                 return li;  
    57.             }  
    58.         }  
    59.   
    60.         public List<ProductDetailsModel> showDetails()  
    61.         {  
    62.             List<ProductDetailsModel> li = new List<ProductDetailsModel>();  
    63.             var details = _dbContext.productDetails;  
    64.             if (details != null)  
    65.             {  
    66.                 Parallel.ForEach(details, x =>  
    67.                 {  
    68.                     ProductDetailsModel obj = new ProductDetailsModel();  
    69.                     obj.slNo = x.slNo;  
    70.                     obj.ProductName = x.ProductName;  
    71.                     obj.Price = Convert.ToInt32(x.Price);  
    72.                     li.Add(obj);  
    73.   
    74.                 });  
    75.                 return li;  
    76.             }  
    77.             else  
    78.             {  
    79.                 return li;  
    80.             }  
    81.   
    82.         }  
    83.   
    84.         public bool DeleteDetails(int id)  
    85.         {  
    86.             var Info = _dbContext.productDetails.Where(m => m.slNo == id).FirstOrDefault();  
    87.             _dbContext.productDetails.Remove(Info);  
    88.             if (_dbContext.SaveChanges() == 0)  
    89.                 return true;  
    90.             return false;  
    91.         }  
    92.     }  
    93. }  
    Now, I will explain the DataLayer, which is used to communicate with the database. Here is the Implementation of this layer.



    Here is my Model1.edmx as follows.This layer will communicate with the database and is responsible for all kinds of DB related operations. Here, we have have used Entityframework, which is an ORM patterm.
As per Microsoft,

The Microsoft ADO.NET Entity Framework is an Object/Relational Mapping (ORM) framework that enables developers to work with relational data as domain-specific objects, eliminating the need for most of the data access plumbing code that developers usually need to write.

Using the Entity Framework, the developers issue queries, using LINQ, and retrieve and manipulate the data as strongly typed objects. The Entity Framework's ORM implementation provides the Services like change tracking, identity resolution, lazy loading and query translation , so that the developers can focus on their Application-specific business logic rather than the data access fundamentals.

Entity framework is an Object/Relational Mapping (O/RM) framework. It is an enhancement to ADO.NET, which gives the developers an automated mechanism to access & store the data in the database.



Now, I will explain how to write code under Web API controller, using Dependency injection.

Let me explain what Dependency Injection is.

Dependency Injection is a technique to develop an Application in an independent way. It is independent in the sense that every module of the Application should be unique and will not depend upon the other modules. They should be loosely coupled.

Let me discuss here what tightly coupled and loosely coupled means in software development.

Tight Coupling

It means two classes or two modules are fully dependent upon each other. Changing one class object may lead to change in several areas in the other class. When we are creating an object of a class and calling that class method by its object from another class, we will say that the two classes are tightly coupled or dependent on each other.

Loose Coupling

It means two objects are independent and an object can use another object without being dependent on it. They are unique. In software development, we always prefer loosely coupling Applications.

Now, I will explain how to use Dependency Injection, using NinJect Container.



Go To Manage NuGet Package, search for Ninject in WEB API Project and install it.

After installing this Ninject, we found the 3 assemblies in our References and one NinjectWebCommon.cs class in App.start, mentioned below.

Here is the NinjectWebCommon.cs class in App.start.

Now, go to NinjectWebCommon.cs class and register the dependency, as shown below.
  1. [assembly: WebActivatorEx.PreApplicationStartMethod(typeof(Demo.Data.App_Start.NinjectWebCommon), "Start")]  
  2. [assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(Demo.Data.App_Start.NinjectWebCommon), "Stop")]  
  3.   
  4. namespace Demo.Data.App_Start  
  5. {  
  6.     using System;  
  7.     using System.Web;  
  8.   
  9.     using Microsoft.Web.Infrastructure.DynamicModuleHelper;  
  10.   
  11.     using Ninject;  
  12.     using Ninject.Web.Common;  
  13.   
  14.     public static class NinjectWebCommon   
  15.     {  
  16.         private static readonly Bootstrapper bootstrapper = new Bootstrapper();  
  17.   
  18.         /// <summary>  
  19.         /// Starts the application  
  20.         /// </summary>  
  21.         public static void Start()   
  22.         {  
  23.             DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));  
  24.             DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));  
  25.             bootstrapper.Initialize(CreateKernel);  
  26.         }  
  27.           
  28.         /// <summary>  
  29.         /// Stops the application.  
  30.         /// </summary>  
  31.         public static void Stop()  
  32.         {  
  33.             bootstrapper.ShutDown();  
  34.         }  
  35.           
  36.         /// <summary>  
  37.         /// Creates the kernel that will manage your application.  
  38.         /// </summary>  
  39.         /// <returns>The created kernel.</returns>  
  40.         private static IKernel CreateKernel()  
  41.         {  
  42.             var kernel = new StandardKernel();  
  43.             try  
  44.             {  
  45.                 kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);  
  46.                 kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();  
  47.   
  48.                 RegisterServices(kernel);  
  49.                 return kernel;  
  50.             }  
  51.             catch  
  52.             {  
  53.                 kernel.Dispose();  
  54.                 throw;  
  55.             }  
  56.         }  
  57.   
  58.         /// <summary>  
  59.         /// Load your modules or register your services here!  
  60.         /// </summary>  
  61.         /// <param name="kernel">The kernel.</param>  
  62.         private static void RegisterServices(IKernel kernel)  
  63.         {    
  64.             kernel.Bind<Demo.IBll.IProduct>().To<Demo.BL.ProductManager>().InRequestScope();  
  65.         }          
  66.     }  
  67. }  
In this way, we need to register the components in Ninject containers. 
Now, I will explain about Repository pattern and how we have achieved it.

REPOSITORY PATTERN

As we are working on a layer architecture, our project must be independent between all the layers. I can say that the Controller layers and DataAccess layers must be independent. If we make it tightly coupled, any change related to the data-access layer can change the controller code.

Without Repository, my code will be, as shown below.



Hence, the repository is used to create an abstraction layer between the Data Access layer and the Business Logic layer of an Application. Implementing these patterns can help insulate your Application from the changes in the data store and can facilitate automated unit testing or test-driven development (TDD).

Here, we are creating an object of Bll in controller, so both the BLL and Controller are tightly coupled. Thus, when our Application becomes tightly coupled, then any change in DAL will change the whole Controller.



Changes are something like changing the database, changing in Data access techinique (ADO.NET Entity Framework, ADO.NET, NHibernate) so any changes will affect the frontend.
 
Suppose my manager is quite unhappy with the performance of Entity framework and advises me to use normal ADO.NET instead of Entity Framework.
 
If our Application is tightly coupled, then it is very difficult to change. If you change the DAL Layer, all the layers in the controller need to change as follows.

 
 
Thus, it will affect both the layers. Here for reference, I have marked with a red arrow mark, where the change may occur. When we are using object of DAL class, it needs to be replaced with SQL DAL class.

Now, let's consider the project, using Repository Pattern. It will look, as shown below.



Here, my controller will point to the IBLL, which is an interface and the Interface will be implemented in BLL.

Suppose we need to change the Entity Framework BAL to normal ADO.NET BAL, Thus, we simply create a ADO.NET BAL and inherit it from IBLL, as shown in the image below.



In this way, we can overcome the problem of frequently changing any data access technology in our projects.

For this reason, we have taken IBLL and BLL in our Project, as shown below.


Now, our project is almost done. We need to write the code in the controller for Dependency Injection and call our respective classes. Thus, my complete code for CRUD operation in ProductDetails controller is as follows.
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Net;  
  5. using System.Net.Http;  
  6. using System.Threading.Tasks;  
  7. using System.Web.Http;  
  8. using Demo.model;  
  9. using Demo.IBll;  
  10.   
  11. namespace WEBAPI.Controllers  
  12. {  
  13.      [RoutePrefix("api/Product")]  
  14.     public class ProductController : ApiController  
  15.     {  
  16.         Demo.IBll.IProduct iproductdetails;  
  17.         public ProductController(Demo.IBll.IProduct _iproductdetails)  
  18.         {  
  19.             iproductdetails = _iproductdetails;  
  20.         }  
  21.          [Route("addProduct")]  
  22.          [HttpPost]  
  23.         public async Task<HttpResponseMessage> saveProductDetails(ProductDetailsModel pod)  
  24.         {  
  25.             Dictionary<stringstring> dict = new Dictionary<stringstring>();  
  26.             bool res = false;  
  27.             
  28.             res = iproductdetails.SaveProducts(pod);  
  29.   
  30.             if (res == true)  
  31.             {  
  32.                 var showmessage = "Product Saved Successfully.";  
  33.   
  34.                 dict.Add("Message", showmessage);  
  35.                 return Request.CreateResponse(HttpStatusCode.OK, dict);  
  36.   
  37.             }  
  38.             else  
  39.             {  
  40.                 var showmessage = "Product Not Saved Please try again.";  
  41.   
  42.                 dict.Add("Message", showmessage);  
  43.                 return Request.CreateResponse(HttpStatusCode.BadRequest, dict);  
  44.   
  45.             }  
  46.         }  
  47.         [Route("showList")]  
  48.         [HttpGet]  
  49.         public async Task<HttpResponseMessage> showList()  
  50.         {  
  51.   
  52.             List<ProductDetailsModel> li = new List<ProductDetailsModel>();  
  53.             Dictionary<stringstring> dict = new Dictionary<stringstring>();  
  54.             var details = iproductdetails.showDetails();  
  55.             foreach (var x in details)  
  56.             {  
  57.                 ProductDetailsModel pcm = new ProductDetailsModel();  
  58.                 pcm.slNo = x.slNo;  
  59.                 pcm.ProductName = x.ProductName;  
  60.                 pcm.Price = x.Price;  
  61.                 li.Add(pcm);  
  62.   
  63.             }  
  64.             return Request.CreateResponse(HttpStatusCode.OK, li);  
  65.   
  66.         }  
  67.   
  68.         [Route("searchProduct")]  
  69.          [HttpPost]  
  70.          public async Task<HttpResponseMessage> searchProduct(ProductDetailsModel pod)  
  71.          {  
  72.               
  73.              List<ProductDetailsModel> li = new List<ProductDetailsModel>();  
  74.              Dictionary<stringstring> dict = new Dictionary<stringstring>();  
  75.              var details = iproductdetails.searchdetails(pod.ProductType);  
  76.              foreach(var x in details)  
  77.              {  
  78.                  ProductDetailsModel pcm = new ProductDetailsModel();  
  79.                  pcm.slNo = x.slNo;  
  80.                  pcm.ProductName = x.ProductName;  
  81.                  pcm.Price = x.Price;  
  82.                  li.Add(pcm);  
  83.                   
  84.              }  
  85.              return Request.CreateResponse(HttpStatusCode.OK,li);  
  86.             
  87.          }  
  88.     }  
  89. }  
Now, save the project. Build it and then check it through Postman client.

In this way, we can create Web API, using Dependency Injection and Repository Layer in our Project.

Hope, you will find some idea about creating Web API, using these techniques. In case you have any doubt about the code written by me, you can comment and I will try to explain it more clearly. If there is any fault in my understanding, I will learn from you.

X

Build smarter apps with Machine Learning, Bots, Cognitive Services - Start free.

Start Learning Now