.Net Core Web API (Dependency Inject - AutoMapper - Repository Pattern)

.Net Core Web API is a framework for building HTTP-based services that can be consumed by different clients, it includes web browsers, mobile applications, etc.

Install Postman

We’re not building a client, we’ll use Postman to test the API. Postman is a web debugging tool that lets you compose HTTP requests and view the raw HTTP responses.

Structure

Below is the diagram which shows the Project structure that we are going to implement. We have divided the API into a different layer

API Layer

It will be used to handle the request and send back the appropriate responses. This layer doesn’t know about the service layer functionality, its main function is to pass the request to the service layer and handle any Global Exception. Authentication and authorization will fall under this layer.

Service Layer

The main role of this layer is to have the business logic as well as to convert the ViewModel object to DTO ( Data Transfer Object) and vise versa. You can have a private validation method to validate the ViewModel object and take necessary actions on it.

DAL

It is known as a Data Access Layer, it is used to communicate with the Databases. It could be SQL Server, MySQL, NoSQL, Redis Cache, etc. We are using Entity Framework In Memory to fetch and post data.

.Net Core Web API (Dependency Inject — AutoMapper — Repository Pattern)

To demonstrate I will be using Visual Studio 2019, but you can use Visual Studio Code as well.

We are going to implement two endpoints.

  • Add Coffee
  • Get Coffee By Id

NOTE
Download/Clone the Github Repo.

GitHub - AnujAngooral/CoffeeShop: CoffeeShop Demo

  • Create a blank solution in the visual studio.
  • Right Click on the solution and add the Asp.Net Core Web API project.
  • Right-click on the solution and add Class Library Project, name it ViewModels.
  • Repeat step 3 for (Dal and services).

Once you are done, you will see something like the below,

.Net Core Web API (Dependency Inject — AutoMapper — Repository Pattern)

API

Open the CoffeeController, it's available in the Controller folder. We have injected two services i.e. ILogger and ICoffeeService. We have three functions “Add, GetById, and Get”.

In the Add function, we are getting the coffee model from the request and we are passing it to the CoffeeService. You can add Authentication, Authorization, and Model validation filters in the controller. But for this demo, we are mainly focusing on the structure.

[HttpPost]
public async Task < IActionResult > Add(Coffee model) {
    var result = await ICoffeeService.AddAsync(model);
    if (result.IsSuccess) return Ok(result.Coffee);
    return StatusCode(500);
}

Services

Let's see how this is implemented in the Services Layer. In this layer, we have added the Automapper NuGet package. This is to convert ViewModel to DTO and vise versa. In this function, we are converting the Viewmodel to DTO and passing it to Data Access Layer to Add and Save the object in the database.

Note
In the response, we are sending back three properties.

  1. IsSuccess
    Which tells the controller/API layer everything is good and data has been saved.
     
  2. Coffee
    This is a coffee object, that we are sending back to the API layer, so further it can send back to the client.
     
  3. ErrorMessage
    If IsSuccess is false, then we will populate this property with the error.
    public async Task < (bool IsSuccess, Coffee Coffee, string ErrorMessage) > AddAsync(ViewModels.Coffee coffee) 
    {
        try {
            var coffeeDTO = _mapper.Map < Dal.Models.Coffee > (coffee);
            await _coffeeRepository.AddAsync(coffeeDTO);
            await _coffeeRepository.CommitAsync();
            coffee.Id = coffeeDTO.Id;
            return (true, coffee, null);
        } catch (Exception ex) {
            _logger.LogError($ "Error: {ex.Message} | {ex.StackTrace}");
            return (false, null, ex.Message);
        }
    }

Dal

In the data access layer, we have used the generic repository. We have a generic IRepository interface, which will handle most of the tasks.

public interface IRepository < T > {
    public Task AddAsync(T entity);
    public Task < T > GetAsync(Expression < Func < T, bool >> filter);
    public Task < IEnumerable < T >> GetAsync();
    public Task CommitAsync();
}

This interface is implemented in the generic Repository Class. We have injected the Dbcontext into the repository constructor. We have a generic DbSet, so we can pass and create the instance of any Entity(DTO). In the GET method, you can return IQueryable<T> which is a better approach.

public class Repository < T > : IRepository < T > where T: class {
    internal CoffeeDbContext dbContext;
    internal DbSet < T > dbSet;
    public Repository(CoffeeDbContext context) {
        this.dbContext = context;
        this.dbSet = context.Set < T > ();
    }
    public async Task AddAsync(T entity) {
        await dbContext.AddAsync(entity);
    }
    public async Task < T > GetAsync(Expression < Func < T, bool >> filter) {
        return await dbSet.FirstAsync(filter);
    }
    public async Task < IEnumerable < T >> GetAsync() {
        return await dbSet.ToListAsync();
    }
    public async Task CommitAsync() {
        await dbContext.SaveChangesAsync();
    }
}

Dependency Injection and Automapper

Open the Startup.cs file present in the API project. We have called Registration.ConfigureServices. This class is available in the services layer, where the services layer registers services interfaces with the services implementation as well as the auto mapper.

services.AddDbContext<CoffeeDbContext>(opt => opt.UseInMemoryDatabase("CoffeeShop"));

The above line requests the Entity framework to use In-Memory Database with the name CoffeeShop.

To register a service, we use the below syntax. Interface name and service name.
services.AddScoped<ICoffeeService, CoffeeService>();

To configure the automapper, we are using the below code.

var mapperConfig = new MapperConfiguration(mc => {
    mc.AddProfile(new MappingProfile());
});
IMapper mapper = mapperConfig.CreateMapper();
services.AddSingleton(mapper);

Make the API project a startup and run it. Open the Postman tool and create a request like below. Send the request, if everything works as expected then you will see the response in the postman with the same data and id property auto-incremented.

.Net Core Web API (Dependency Inject — AutoMapper — Repository Pattern)

The other Get functions also follow the same structure, so I am not going to explain it. You guys can go through it and let me know if you have any doubt, then we can discuss them as well.