Creating An Application From Scratch Using .NET Core and Angular - Part 3 - by Henrique Siebert Domareski - Medium
Creating An Application From Scratch Using .NET Core and Angular - Part 3 - by Henrique Siebert Domareski - Medium
atch using .NET Core and Angular — Part 3 | by Henrique Siebert Domareski | Medium
Search
Listen Share
In this article we are going to see how to create the Interfaces and the Services,
which will be responsible for the business rule of our application, in the Domain
layer, and we also are going to create the Repositories using the Repository pattern
in the Infrastructure layer to access and execute the operations in the database.
This pattern it’s used in a lot of projects and brings a lot of benefits. Some
advantages of this pattern are:
https://henriquesd.medium.com/creating-an-application-from-scratch-using-net-core-and-angular-part-3-e3c42cd9cc01 1/25
15/02/2024 09:25 Creating an Application from Scratch using .NET Core and Angular — Part 3 | by Henrique Siebert Domareski | Medium
Allows the isolation of the business layer (the domain layer) of the database
layer (the infrastructure layer).
Allows the change of a database in the future (if necessary) without having much
impact in the system
You have all the code for access the database in one place
Easy to maintain
Repositories are classes or components that encapsulate the logic required to access data
sources. They centralize common data access functionality, providing better
maintainability and decoupling the infrastructure or technology used to access databases
from the domain model layer.
Using this pattern, we are going to have a generic class for the Repository with the
basic operations (Add, Get, GetById, Remove, Update, Search, Save), and we are
going to have specific classes for specific actions that we need, that goes beyond the
basic operations. So let’s start creating the interfaces.
Domain Layer
In this layer, we will have the Interfaces and the Services. We are going to use the
Interfaces to work with Dependency injection, that is the letter D of the SOLID
principles, that is Dependency Inversion Principle (also known as IoC — Inversion of
Control). I will not explain about SOLID for now because it’s not the focus of this
article, but it’s good to understand what says this principle:
High-level modules should not depend on low-level modules. Both should depend on
abstractions. Abstractions should not depend on details. Details should depend on
abstractions.
abstraction). Doing that, if something change in the class, the other classes will not
be affected because it depends on an abstraction.
The Services classes are where we are going to add the business rules of the
application. Those classes are between the Controller and the Repository. The
application layer should not have access to the infrastructure layer, so we are going
to use the services classes in the domain layer as an intermediate between the
controllers in the application layer and the repositories in the infrastructure layer.
Also, we should not add business rules in the controller, so the controllers will call
the services where we will concentrate the business rules, and the services will call
the repository.
Interfaces
We need to create a folder for the Interfaces, and create all the interfaces that we are
going to use:
Generic Interface
Let’s start implementing the generic interface IRepository. This interface it’s for the
generic Repository class that we are going to create in the Infrastructure layer. For
this class we need the signature for the CRUD (Create, Read, Update, Delete)
operation, and also a method for saving the changes and for search:
https://henriquesd.medium.com/creating-an-application-from-scratch-using-net-core-and-angular-part-3-e3c42cd9cc01 3/25
15/02/2024 09:25 Creating an Application from Scratch using .NET Core and Angular — Part 3 | by Henrique Siebert Domareski | Medium
1 using System;
2 using System.Collections.Generic;
3 using System.Linq.Expressions;
4 using System.Threading.Tasks;
5 using BookStore.Domain.Models;
6
7 namespace BookStore.Domain.Interfaces
8 {
9 public interface IRepository<TEntity> : IDisposable where TEntity : Entity
10 {
11 Task Add(TEntity entity);
12 Task<List<TEntity>> GetAll();
13 Task<TEntity> GetById(int id);
14 Task Update(TEntity entity);
15 Task Remove(TEntity entity);
16 Task<IEnumerable<TEntity>> Search(Expression<Func<TEntity, bool>> predicate);
17 Task<int> SaveChanges();
18 }
19 }
In the Repository class that we are going to create in the Infrastructure project, we
are going to implement this interface. You can see that in this class we have all the
basic operations:
The GetAll method it’s to get all records for the entity.
The Search method it’s for searching an entity passing a lambda expression to search
any entity with any parameter. This predicate it’s an expression, so you can use a
lambda expression to filter objects, it’s exactly the same way we use the where with
linq.
The SaveChanges it’s for save the changes of the entity. It will return an int, that will
be the number of lines that were affected by the save action.
https://henriquesd.medium.com/creating-an-application-from-scratch-using-net-core-and-angular-part-3-e3c42cd9cc01 4/25
15/02/2024 09:25 Creating an Application from Scratch using .NET Core and Angular — Part 3 | by Henrique Siebert Domareski | Medium
The class that will implement this interface, also need to implement the interface
IDisposible for release memory.
Specific interfaces
For the BookRepository class (that we are going to implement in the Infrastructure
layer), we are not going to use the GetById and the GetAll from the generic class,
because we want to return the category of the book in those methods. If we use the
methods from the generic Repository class, it will not bring the name of the
category, so we will have a specific GetAll and GetById for this class. We will also
have a method that will allow returning the books filtered by a category. So the
interface IBookRepository will inherit from IRepository<Book>, and we will have
those specific methods:
GetAll — this method we are going to override because we need to add the
category name in the result
GetById — this method will also be overridden to allow returning the category
name
1 using System.Collections.Generic;
2 using System.Threading.Tasks;
3 using BookStore.Domain.Models;
4
5 namespace BookStore.Domain.Interfaces
6 {
7 public interface IBookRepository : IRepository<Book>
8 {
9 new Task<List<Book>> GetAll();
10 new Task<Book> GetById(int id);
11 Task<IEnumerable<Book>> GetBooksByCategory(int categoryId);
12 Task<IEnumerable<Book>> SearchBookWithCategory(string searchedValue);
13 }
14 }
We need the ‘new’ in the line 9 and 10, because those 2 methods will be overridden
in the BookRepository class.
https://henriquesd.medium.com/creating-an-application-from-scratch-using-net-core-and-angular-part-3-e3c42cd9cc01 5/25
15/02/2024 09:25 Creating an Application from Scratch using .NET Core and Angular — Part 3 | by Henrique Siebert Domareski | Medium
1 using BookStore.Domain.Models;
2
3 namespace BookStore.Domain.Interfaces
4 {
5 public interface ICategoryRepository : IRepository<Category>
6 {
7
8 }
9 }
In the IBookService we have the signature of the methods about the CRUD
operations and also the GetBooksByCategory, which will receive a category id as a
parameter and will return a list of books that have that category id:
1 using System;
2 using System.Collections.Generic;
3 using System.Threading.Tasks;
4 using BookStore.Domain.Models;
5
6 namespace BookStore.Domain.Interfaces
7 {
8 public interface IBookService : IDisposable
9 {
10 Task<IEnumerable<Book>> GetAll();
11 Task<Book> GetById(int id);
12 Task<Book> Add(Book book);
13 Task<Book> Update(Book book);
14 Task<bool> Remove(Book book);
15 Task<IEnumerable<Book>> GetBooksByCategory(int categoryId);
16 Task<IEnumerable<Book>> Search(string bookName);
17 Task<IEnumerable<Book>> SearchBookWithCategory(string searchedValue);
18 }
19 }
In the ICategoryService we also have the signature of the methods about the CRUD
operations:
https://henriquesd.medium.com/creating-an-application-from-scratch-using-net-core-and-angular-part-3-e3c42cd9cc01 6/25
15/02/2024 09:25 Creating an Application from Scratch using .NET Core and Angular — Part 3 | by Henrique Siebert Domareski | Medium
1 using System;
2 using System.Collections.Generic;
3 using System.Threading.Tasks;
4 using BookStore.Domain.Models;
5
6 namespace BookStore.Domain.Interfaces
7 {
8 public interface ICategoryService : IDisposable
9 {
10 Task<IEnumerable<Category>> GetAll();
11 Task<Category> GetById(int id);
12 Task<Category> Add(Category category);
13 Task<Category> Update(Category category);
14 Task<bool> Remove(Category category);
15 Task<IEnumerable<Category>> Search(string categoryName);
16 }
17 }
For both classes, the method GetAll will return a list of object. The Add, the Update
and the GetById methods will return the object, and the remove method will return
the number of lines that were affected.
Note that for those two interfaces we also need to implement the Disposable, and
the reason for that it’s because this is used for memory release.
Services
Now let’s create the ‘Services’ folder, and create the CategoryService and the
BookService classes. On the Services class is where we are going to add the business
rules:
https://henriquesd.medium.com/creating-an-application-from-scratch-using-net-core-and-angular-part-3-e3c42cd9cc01 7/25
15/02/2024 09:25 Creating an Application from Scratch using .NET Core and Angular — Part 3 | by Henrique Siebert Domareski | Medium
For Category it is only possible to add a category if the informed name does not exist
in the database yet. And it is only possible to remove a category if there are no books
using the category.
https://henriquesd.medium.com/creating-an-application-from-scratch-using-net-core-and-angular-part-3-e3c42cd9cc01 8/25
15/02/2024 09:25 Creating an Application from Scratch using .NET Core and Angular — Part 3 | by Henrique Siebert Domareski | Medium
1 using System.Collections.Generic;
2 using System.Linq;
3 using System.Threading.Tasks;
4 using BookStore.Domain.Interfaces;
5 using BookStore.Domain.Models;
6
7 namespace BookStore.Domain.Services
8 {
9 public class CategoryService : ICategoryService
10 {
11 private readonly ICategoryRepository _categoryRepository;
12 private readonly IBookService _bookService;
13
14 public CategoryService(ICategoryRepository categoryRepository, IBookService bookService
15 {
16 _categoryRepository = categoryRepository;
17 _bookService = bookService;
18 }
19
20 public async Task<IEnumerable<Category>> GetAll()
21 {
22 return await _categoryRepository.GetAll();
23 }
24
25 public async Task<Category> GetById(int id)
26 {
27 return await _categoryRepository.GetById(id);
28 }
29
30 public async Task<Category> Add(Category category)
31 {
32 if (_categoryRepository.Search(c => c.Name == category.Name).Result.Any())
33 return null;
34
35 await _categoryRepository.Add(category);
36 return category;
37 }
38
39 public async Task<Category> Update(Category category)
40 {
41 if (_categoryRepository.Search(c => c.Name == category.Name && c.Id != category.Id)
42 return null;
43
44 await _categoryRepository.Update(category);
45 return category;
46 }
47
48 public async Task<bool> Remove(Category category)
https://henriquesd.medium.com/creating-an-application-from-scratch-using-net-core-and-angular-part-3-e3c42cd9cc01 9/25
15/02/2024 09:25 Creating an Application from Scratch using .NET Core and Angular — Part 3 | by Henrique Siebert Domareski | Medium
48 public async Task<bool> Remove(Category category)
49 {
50 var books = await _bookService.GetBooksByCategory(category.Id);
51 if (books.Any()) return false;
52
53 await _categoryRepository.Remove(category);
54 return true;
55 }
56
57 public async Task<IEnumerable<Category>> Search(string categoryName)
58 {
59 return await _categoryRepository.Search(c => c.Name.Contains(categoryName));
60 }
61
62 public void Dispose()
63 {
64 _categoryRepository?.Dispose();
65 }
66 }
67 }
Note that we are using Dependency Injection to pass the ICategoryRepository in the
constructor of our class. This way the class do not depends on a concrete class, but
depends on an abstraction (the interface).
In the BookService, we will implement the interface IBookService. For this class will
also have the rule that will not allow to register two books with the same name. This
is the BookService.cs:
https://henriquesd.medium.com/creating-an-application-from-scratch-using-net-core-and-angular-part-3-e3c42cd9cc01 10/25
15/02/2024 09:25 Creating an Application from Scratch using .NET Core and Angular — Part 3 | by Henrique Siebert Domareski | Medium
1 using System.Collections.Generic;
2 using System.Linq;
3 using System.Threading.Tasks;
4 using BookStore.Domain.Interfaces;
5 using BookStore.Domain.Models;
6
7 namespace BookStore.Domain.Services
8 {
9 public class BookService : IBookService
10 {
11 private readonly IBookRepository _bookRepository;
12
13 public BookService(IBookRepository bookRepository)
14 {
15 _bookRepository = bookRepository;
16 }
17
18 public async Task<IEnumerable<Book>> GetAll()
19 {
20 return await _bookRepository.GetAll();
21 }
22
23 public async Task<Book> GetById(int id)
24 {
25 return await _bookRepository.GetById(id);
26 }
27
28 public async Task<Book> Add(Book book)
29 {
30 if (_bookRepository.Search(b => b.Name == book.Name).Result.Any())
31 return null;
32
33 await _bookRepository.Add(book);
34 return book;
35 }
36
37 public async Task<Book> Update(Book book)
38 {
39 if (_bookRepository.Search(b => b.Name == book.Name && b.Id != book.Id).Result.Any(
40 return null;
41
42 await _bookRepository.Update(book);
43 return book;
44 }
45
46 public async Task<bool> Remove(Book book)
47 {
48 await bookRepository Remove(book);
https://henriquesd.medium.com/creating-an-application-from-scratch-using-net-core-and-angular-part-3-e3c42cd9cc01 11/25
15/02/2024 09:25 Creating an Application from Scratch using .NET Core and Angular — Part 3 | by Henrique Siebert Domareski | Medium
48 await _bookRepository.Remove(book);
49 return true;
50 }
51
52 public async Task<IEnumerable<Book>> GetBooksByCategory(int categoryId)
53 {
54 return await _bookRepository.GetBooksByCategory(categoryId);
55 }
56
57 public async Task<IEnumerable<Book>> Search(string bookName)
58 {
59 return await _bookRepository.Search(c => c.Name.Contains(bookName));
60 }
61
62 public async Task<IEnumerable<Book>> SearchBookWithCategory(string searchedValue)
63 {
64 return await _bookRepository.SearchBookWithCategory(searchedValue);
65 }
66
67 public void Dispose()
68 {
69 _bookRepository?.Dispose();
70 }
71 }
72 }
Before we call the Add or Update method, we need to validate if the name is already
being used. So first we will search if already exists a book with the informed name,
and if does not exist, then we can call the Add or Update.
Infrastructure Layer
Let’s create now the ‘Repositories’ folder, and create the Repository, BookRepository
and CategoryRepository classes:
https://henriquesd.medium.com/creating-an-application-from-scratch-using-net-core-and-angular-part-3-e3c42cd9cc01 12/25
15/02/2024 09:25 Creating an Application from Scratch using .NET Core and Angular — Part 3 | by Henrique Siebert Domareski | Medium
Generic Repository
https://henriquesd.medium.com/creating-an-application-from-scratch-using-net-core-and-angular-part-3-e3c42cd9cc01 13/25
15/02/2024 09:25 Creating an Application from Scratch using .NET Core and Angular — Part 3 | by Henrique Siebert Domareski | Medium
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Linq.Expressions;
5 using System.Threading.Tasks;
6 using BookStore.Domain.Interfaces;
7 using BookStore.Domain.Models;
8 using BookStore.Infrastructure.Context;
9 using Microsoft.EntityFrameworkCore;
10
11 namespace BookStore.Infrastructure.Repositories
12 {
13 public abstract class Repository<TEntity> : IRepository<TEntity> where TEntity : Entity
14 {
15 protected readonly BookStoreDbContext Db;
16
17 protected readonly DbSet<TEntity> DbSet;
18
19 protected Repository(BookStoreDbContext db)
20 {
21 Db = db;
22 DbSet = db.Set<TEntity>();
23 }
24
25 public async Task<IEnumerable<TEntity>> Search(Expression<Func<TEntity, bool>> predicat
26 {
27 return await DbSet.AsNoTracking().Where(predicate).ToListAsync();
28 }
29
30 public virtual async Task<TEntity> GetById(int id)
31 {
32 return await DbSet.FindAsync(id);
33 }
34
35 public virtual async Task<List<TEntity>> GetAll()
36 {
37 return await DbSet.ToListAsync();
38 }
39
40 public virtual async Task Add(TEntity entity)
41 {
42 DbSet.Add(entity);
43 await SaveChanges();
44 }
45
46 public virtual async Task Update(TEntity entity)
47 {
48 DbSet Update(entity);
https://henriquesd.medium.com/creating-an-application-from-scratch-using-net-core-and-angular-part-3-e3c42cd9cc01 14/25
15/02/2024 09:25 Creating an Application from Scratch using .NET Core and Angular — Part 3 | by Henrique Siebert Domareski | Medium
48 DbSet.Update(entity);
49 await SaveChanges();
50 }
51
52 public virtual async Task Remove(TEntity entity)
53 {
54 DbSet.Remove(entity);
55 await SaveChanges();
56 }
57
58 public async Task<int> SaveChanges()
59 {
60 return await Db.SaveChangesAsync();
61 }
62
63 public void Dispose()
64 {
65 Db?.Dispose();
66 }
67 }
68 }
This is an abstract class, which means that this class cannot be instantiated, it can
only be inherited. All specific repositories classes that we are going to create, will
inherit from this main class. On this class, we need to implemented the methods
from the Interface IRepository.
The Db property is protected because all classes that will inheritance from
Repository, can access the Db property.
The property DbSet is used as a shortcut to execute the operations in the database.
There some methods that are virtual, and the reason for that it’s because we want to
allow to do an override in other specific repository class if necessary. This is from
the Microsoft official documentation:
The virtual keyword is used to modify a method, property, indexer, or event declaration
and allow for it to be overridden in a derived class.
We implement the Dispose method because this is used to release memory in our
application:
https://henriquesd.medium.com/creating-an-application-from-scratch-using-net-core-and-angular-part-3-e3c42cd9cc01 15/25
15/02/2024 09:25 Creating an Application from Scratch using .NET Core and Angular — Part 3 | by Henrique Siebert Domareski | Medium
Implementing the Dispose method is primarily for releasing unmanaged resources used by
your code.
In the Search method, we are using the AsNoTracking() because when we add
something in the memory, the object will be tracking, so in this case that we are
only reading something in the database, we can use AsNoTracking to increase
performance in our application. We can see this information in the official
Microsoft documentation:
No tracking queries are useful when the results are used in a read-only scenario. They’re
quicker to execute because there’s no need to set up the change tracking information. If you
don’t need to update the entities retrieved from the database, then a no-tracking query
should be used.
Specific Repositories
We also need to create the specifics repositories classes for the CategoryRepository
and the BookRepository. In the CategoryRepository class we will inherit from
Repository<Category>:
1 using BookStore.Domain.Interfaces;
2 using BookStore.Domain.Models;
3 using BookStore.Infrastructure.Context;
4
5 namespace BookStore.Infrastructure.Repositories
6 {
7 public class CategoryRepository : Repository<Category>, ICategoryRepository
8 {
9 public CategoryRepository(BookStoreDbContext context) : base(context) { }
10 }
11 }
https://henriquesd.medium.com/creating-an-application-from-scratch-using-net-core-and-angular-part-3-e3c42cd9cc01 16/25
15/02/2024 09:25 Creating an Application from Scratch using .NET Core and Angular — Part 3 | by Henrique Siebert Domareski | Medium
1 using System.Collections.Generic;
2 using System.Linq;
3 using System.Threading.Tasks;
4 using BookStore.Domain.Interfaces;
5 using BookStore.Domain.Models;
6 using BookStore.Infrastructure.Context;
7 using Microsoft.EntityFrameworkCore;
8
9 namespace BookStore.Infrastructure.Repositories
10 {
11 public class BookRepository : Repository<Book>, IBookRepository
12 {
13 public BookRepository(BookStoreDbContext context) : base(context) { }
14
15 public override async Task<List<Book>> GetAll()
16 {
17 return await Db.Books.AsNoTracking().Include(b => b.Category)
18 .OrderBy(b => b.Name)
19 .ToListAsync();
20 }
21
22 public override async Task<Book> GetById(int id)
23 {
24 return await Db.Books.AsNoTracking().Include(b => b.Category)
25 .Where(b => b.Id == id)
26 .FirstOrDefaultAsync();
27 }
28
29 public async Task<IEnumerable<Book>> GetBooksByCategory(int categoryId)
30 {
31 return await Search(b => b.CategoryId == categoryId);
32 }
33
34 public async Task<IEnumerable<Book>> SearchBookWithCategory(string searchedValue)
35 {
36 return await Db.Books.AsNoTracking()
37 .Include(b => b.Category)
38 .Where(b => b.Name.Contains(searchedValue) ||
39 b.Author.Contains(searchedValue) ||
40 b.Description.Contains(searchedValue) ||
41 b.Category.Name.Contains(searchedValue))
42 .ToListAsync();
43 }
44 }
45 }
https://henriquesd.medium.com/creating-an-application-from-scratch-using-net-core-and-angular-part-3-e3c42cd9cc01 17/25
15/02/2024 09:25 Creating an Application from Scratch using .NET Core and Angular — Part 3 | by Henrique Siebert Domareski | Medium
Now we can commit the code in GitHub. In the next part, we are going to create the
Controllers in the API layer and see how we can document the API using Swagger.
We also are going to using AutoMapper to mapping our entities to Dtos objects. You
can access the part 4 clicking here.
https://github.com/henriquesd/BookStore
If you like this project, I kindly ask you to give a ⭐️ in the repository.
References
Repository Pattern
https://henriquesd.medium.com/creating-an-application-from-scratch-using-net-core-and-angular-part-3-e3c42cd9cc01 18/25
15/02/2024 09:25 Creating an Application from Scratch using .NET Core and Angular — Part 3 | by Henrique Siebert Domareski | Medium
Follow
44 1
https://henriquesd.medium.com/creating-an-application-from-scratch-using-net-core-and-angular-part-3-e3c42cd9cc01 19/25
15/02/2024 09:25 Creating an Application from Scratch using .NET Core and Angular — Part 3 | by Henrique Siebert Domareski | Medium
43
Primary Constructors is a feature that was already present in C# 9 but it was restricted to
record types, and now with C# 12 this feature…
97
337 10
Vinod Pal
12
Jaydeep Patil
https://henriquesd.medium.com/creating-an-application-from-scratch-using-net-core-and-angular-part-3-e3c42cd9cc01 22/25
15/02/2024 09:25 Creating an Application from Scratch using .NET Core and Angular — Part 3 | by Henrique Siebert Domareski | Medium
66
Lists
13
https://henriquesd.medium.com/creating-an-application-from-scratch-using-net-core-and-angular-part-3-e3c42cd9cc01 23/25
15/02/2024 09:25 Creating an Application from Scratch using .NET Core and Angular — Part 3 | by Henrique Siebert Domareski | Medium
Crafting-Code
37
Suminda Niroshan
https://henriquesd.medium.com/creating-an-application-from-scratch-using-net-core-and-angular-part-3-e3c42cd9cc01 24/25
15/02/2024 09:25 Creating an Application from Scratch using .NET Core and Angular — Part 3 | by Henrique Siebert Domareski | Medium
Microsoft Power Apps are extremely popular with organisations who needs a reliable platform
to make business applications.
51
61
https://henriquesd.medium.com/creating-an-application-from-scratch-using-net-core-and-angular-part-3-e3c42cd9cc01 25/25