| by Achyut Kendre | No comments

What is Repository and DI Pattern? How to use it in ASP.NET Core?

ASP.NET Core
ASP.NET Core Tutorial

Example Code: https://drive.google.com/file/d/13duW6-CGJuG8Ig4zNy0-OUvyqqS_H3Im/view?usp=sharing

What is Repository and DI pattern?

Let us first understand with is repository design pattern and dependency injections then we will use the model using this.

What is Repository Design Pattern ?

Repository design pattern allow you to separate the data access code in separate unit (class) called Repository so that we can re use that data access code again and again at multiple locations in your application. This pattern also makes it easy to define data access policies since all data is at central location in repositories.

Use repositories directly in controller will tightly couple the controller with that repository. If you want them to be decoupled then we need to use the dependency Injection Pattern.

Dependency Injection Pattern

What dependency injection pattern says if one class depends on another class called dependency instead of creating object of that class (dependency class) in dependent class create it’s object some where outside the dependent class and inject it using dependency injection.

So to achieve above we need to introduce the abstraction between two classes. What DIP Says, is High-level modules should not depend on low-level modules. Both should depend on the abstraction. Abstractions should not depend on details. Details should depend on abstractions. There are three types of injections we can use –

Constructor Injection: In the constructor injection, the injector supplies the service (dependency) through the client class constructor.

Property Injection: In the property injection (aka the Setter Injection), the injector supplies the dependency through a public property of the client class.

Method Injection: In this type of injection, the client class implements an interface which declares the method(s) to supply the dependency and the injector uses this interface to supply the dependency to the client class.

Let us understand this by example, assume we have a classes as follows –

class SMSSender
{
   public void Send()
   {
     //sms sending code
   }
}

class Notify
{
   SMSSender s;
   public Notify()
   {
     s =new SMSSender();
   }
  public void notify()
  {
    s.Send();   
  }
}

So if you look at these classes these class are tightly coupled. Notify is tightly coupled with SMSSender since we are creating the object of SMSSender in Notify here notify is called dependent class and SMSSender is called Dependency.
What DI say’s is instead of creating the object of SMSSender directly inside notify class create it some where outside the notify class and inject it using dependency injections.
To resolve this dependency we need to introduce the abstraction interface between them as follows where we will create the object of SMSSender outside the Notify class and inject it using constructor injection.

Solution is –

Interface INotify
{
  void Send();
}
class SMSSender:INotify
{
   public void Send()
   {
     //sms sending code
   }
}

class Notify
{
   INotify s;
   public Notify(INotify temp)
   {
     s =temp;
   }
  public void notify()
  {
    s.Send();   
  }
}

SMSSender sm =new SMSSender()
Notify n=new Notify(sm);

ASP.NET Core is designed from scratch to support Dependency Injection. ASP.NET Core injects objects of dependency classes through constructor or method by using built-in IoC container. ASP.NET Core framework contains simple out-of-the-box IoC container.

The built-in container is represented by IServiceProvider implementation that supports constructor injection by default. The types (classes) managed by built-in IoC container are called services.

There are basically two types of services in ASP.NET Core:

Framework Services: Services which are a part of ASP.NET Core framework such as IApplicationBuilder, IHostingEnvironment, ILoggerFactory etc.
Application Services: The services (custom types or classes) which you as a programmer create for your application.
In order to let the IoC container automatically inject our application services, we first need to register them with IoC container.

Registering Application Service

Consider the following example of simple ILog interface and its implementation class. We will see how to register it with built-in IoC container and use it in our application.


public interface ILog
{
    void info(string str);
}

class MyConsoleLogger : ILog
{
    public void info(string str)
    {
        Console.WriteLine(str);
    }
}

ASP.NET Core allows us to register our application services with IoC container, in the ConfigureServices method of the Startup class. The ConfigureServices method includes a parameter of IServiceCollection type which is used to register application services.
To register the above service to IOC we have following three extension methods –

ASP.NET Core allows us to register our application services with IoC container, in the ConfigureServices method of the Startup class. The ConfigureServices method includes a parameter of IServiceCollection type which is used to register application services. To register the above service to IOC we have following three extension methods –

AddSingleton<Interface,ServiceClass>(); e.g. AddSingleton<ILog, MyConsoleLogger>();
AddTransient<Interface, MyConsoleLogger>();e.g. AddTransient<ILog, MyConsoleLogger>();
AddScoped<Interface,ServiceClass>(); e.g.AddScoped<ILog, MyConsoleLogger>();

These method also defines the life time of service.

Understanding Service Lifetime

Built-in IoC container manages the lifetime of a registered service type. It automatically disposes a service instance based on the specified lifetime.

The built-in IoC container supports three kinds of lifetimes:

Singleton: IoC container will create and share a single instance of a service throughout the application’s lifetime.
Transient: The IoC container will create a new instance of the specified service type every time you ask for it.
Scoped: IoC container will create an instance of the specified service type once per request and will be shared in a single request.

Extension Methods for Registration

ASP.NET Core framework includes extension methods for each types of lifetime; AddSingleton(), AddTransient() and AddScoped() methods for singleton, transient and scoped lifetime respectively.

The following example shows the ways of registering types (service) using extension methods.

AddSingleton<ILog, MyConsoleLogger>();
AddTransient<ILog, MyConsoleLogger>();
AddScoped<ILog, MyConsoleLogger>();

Constructor Injection

Once we register a service, the IoC container automatically performs constructor injection if a service type is included as a parameter in a constructor.

For example, we can use ILog service type in any MVC controller. Consider the following example.

public class HomeController : Controller
{
    ILog _log;

    public HomeController(ILog log)
    {
        _log = log;
    }
    public IActionResult Index()
    {
        _log.info("Executing /home/index");

        return View();
    }
}

Using Model in ASP.NET Core by Repository Design Pattern with Dependency Injections.

Let us do it step by step.

Step 1: Create ASP.NET Core Empty project as we learnt in previous article.

Step 2: Add a Models folder and create the Model in it as follows –

namespace ModelUsingRepoandDIEx.Models
{
    public class Customer
    {
        public Int64 CustomerID { get; set; }
        public string CustomerName { get; set; }
        public string Address { get; set; }
        public string EmailID { get; set; }
        public string MobileNo { get; set; }
        public decimal CreditLimit { get; set; }
    }
}

Now create a folder Repositories and create ICustomer Interface as follows –

 public interface ICustomer
    {
        List<Customer> GetAllCustomers();
        void AddCustomer(ICustomer rec);
    }

Now add a CustomerRepo class in the same folder where implement ICustomr Interface as follows-

 public class CustomerRepo : ICustomer
    {
       
        CustomerRepo()
        {
          
        }
        public void AddCustomer(ICustomer rec)
        {
            //throw new NotImplementedException();
        }

        public List<Customer> GetAllCustomers()
        {
           List<Customer> lst=new List<Customer> ();
            lst.Add(new Customer() { CustomerID = 1, CustomerName = "Ganesh", Address = "Nigdi", CreditLimit = 45000, EmailID = "Ganesh@gmail.com", MobileNo = "999575675" });
            lst.Add(new Customer() { CustomerID = 2, CustomerName = "Suresh", Address = "Chinchwad", CreditLimit = 75000, EmailID = "Suresh@gmail.com", MobileNo = "888575675" });
            lst.Add(new Customer() { CustomerID = 3, CustomerName = "Anil", Address = "Nigdi", CreditLimit = 48000, EmailID = "anil@gmail.com", MobileNo = "78988575675" });
            lst.Add(new Customer() { CustomerID = 4, CustomerName = "Amol", Address = "Akurdi", CreditLimit = 90000, EmailID = "amol@gmail.com", MobileNo = "9998875675" });
            lst.Add(new Customer() { CustomerID = 5, CustomerName = "Ajit", Address = "Nigdi", CreditLimit = 11000, EmailID = "ajit@gmail.com", MobileNo = "9988855675" });
           return lst;
        }
    }

Now register this interface and class to ASP.NET Core in startup.cs class in ConfigureService as follows –

public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            //most recommended option
            services.AddControllersWithViews();
            services.AddScoped<ICustomer, CustomerRepo>();
            //services.AddSingleton<ICustomer, CustomerRepo>();
            //services.AddTransient<ICustomer, CustomerRepo>();

        }
}

Now create a controller called HomeController and ask for the CustomerRepo service using Constructor Injection as follows –

public class HomeController : Controller
    {
        ICustomer ic;
        public HomeController(ICustomer temp)
        {
            ic = temp;
        }
        public IActionResult Index()
        {
            return View(ic.GetAllCustomers());
        }
    }

Now create a Index.cshtml file as follows –

@model IEnumerable<ModelUsingRepoandDIEx.Models.Customer>
@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
       <h2> Customer Info </h2>
       <table>
          <tr>
              <td>Customer ID</td>
              <td>Customr Name</td>
              <td>Address</td>
              <td>Email Id</td>
              <td>Mobile No</td>
              <td>Credit Limit</td>
          </tr>
          @foreach (var temp in Model)
          { 
       <tr>
           <td>@temp.CustomerID</td>
           <td>@temp.CustomerName</td>
           <td>@temp.Address</td>
           <td>@temp.EmailID</td>
           <td>@temp.MobileNo</td>
           <td>@temp.CreditLimit</td>
       </tr>
          }
       </table>
</body>
</html>