How To Create A Blog In Asp.net Using C
In this extensive guide, we will go through everything you will need to know about Repository Pattern in ASP.NET Core, Generic Repository Patterns, Unit of Work and related topics. We will build a project right from scratch where we implement a clean architecture to access data. The source code of this implemenation is over at my Github.
What's a Repository Pattern?
A Repository pattern is a design pattern that mediates data from and to the Domain and Data Access Layers ( like Entity Framework Core / Dapper). Repositories are classes that hide the logics required to store or retreive data. Thus, our application will not care about what kind of ORM we are using, as everything related to the ORM is handled within a repository layer. This allows you to have a cleaner seperation of concerns. Repository pattern is one of the heavily used Design Patterns to build cleaner solutions.
Benefits of Repository Pattern
Reduces Duplicate Queries
Imagine having to write lines of code to just fetch some data from your datastore. Now what if this set of queries are going to be used in multiple places in the application. Not very ideal to write this code over and over again, right? Here is the added advantage of Repository Classes. You could write your data access code within the Repository and call it from multiple Controllers / Libraries. Get the point?
De-couples the application from the Data Access Layer
There are quite a lot of ORMs available for ASP.NET Core. Currently the most popular one is Entity Framework Core. But that change in the upcoming years. To keep in pace with the evolving technologies and to keep our Solutions upto date, it is highly crucial to build applications that can switch over to a new DataAccessTechnology with minimal impact on our application's code base.
There can be also cases where you need to use multiple ORMs in a single solution. Probably Dapper to fetch the data and EFCore to write the data. This is solely for performance optimizations.
Repository pattern helps us to achieve this by creating an Abstration over the DataAccess Layer. Now, you no longer have to depend on EFCore or any other ORM for your application. EFCore becomes one of your options rather than your only option to access data.
The Architecture should be independent of the Frameworks.
– Uncle Bob ( Robert Cecil Martin )
Building an Enterprise level ASP.NET Core Application would really need Repository Patterns to keep the codebase future proof for atleast the next 20-25 years (After which, probably the robots would take over 😛 ).
Is Repository Pattern Dead?
This is one of the most debated topics within the .NET Core Community. Microsoft has built the Entity Framework Core using the Repository Pattern and Unit of Work Patterns. So, why do we need to add another layer of abstraction over the Entity Framework Core, which is yet another abstration of Data Access. The answer to this is also given by Microsoft.
Read more here – https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/infrastructure-persistence-layer-implemenation-entity-framework-core#using-a-custom-repository-versus-using-ef-dbcontext-directly
Microsoft themselves recommend using Repository Patterns in complex scenarios to reduce the coupling and provide better Testability of your solutions. In cases where you want the simplest possible code, you would want to avoid the Repository Pattern.
Adding the Repository has it's own benefits too. But i strongly advice to not use Design Patterns everywhere. Try to use it only whenever the scenario demands the usage of a Design Pattern. That being stated, Repository pattern is something that can benefit you in the long run.
Implementing Repository Pattern in ASP.NET Core 3.1
Let's implement Repository Pattern in an ASP.NET Core WebApi Project. What seperates this guide from the others is that we will also be working with a Clean Architecture in mind to demonstrate the real-life implementation. This means that we will be working with multiple Layers and Projects and also go through the basics of Dependency Inversion Principle.
PS, I am using Visual Studio 2019 Community as my default IDE. Read this article to install this awesome IDE on to your machine.
Let's start by creating a new Solution. Here I am naming my Solution as RepositoryPattern.WebApi and the first project as WebApi (ASP.NET Core).
Simalary, let's add 2 more .NET Core Class Library Projects within the solution. We will call it DataAccess.EFCore and Domain. Here are the features and purposes of each project.
- Domain – Holds the Entities and Interfaces. It does not depend on any other project in the solution.
- DataAccess,EFCore – Since we will be using Entity Framework Core – Code First Apporach to interact with our Database, let's build a project that solely represents everything related to EFCore. The aim is that, later down the road one can easily build another Data Access layer like DataAccess.Dapper or so. And our application would still support it. Here is where Dependency Inversion comes to play.
- WebApi – This is like the presentation layer of the entire solution. It depends on both the projects.
Here is how our Solution would look like now.
Setting up the Entities and EFCore
Now, let's add the Required Entities to the Domain Project. Create a new Folder in the Domain Project named Entities.
Create 2 very simple classes – Developer and Project under the Entities Folder.
public class Developer { public int Id { get; set; } public string Name { get; set; } public int Followers { get; set; } }
public class Project { public int Id { get; set; } public string Name { get; set; } }
Next , we will setup and configure Entity Framework Core. Install these Required Packages in the DataAccess.EFCore Project. Here is where we would have our DbContect Class and the actual Implementations of the Repositories.
Install-Package Microsoft.EntityFrameworkCore Install-Package Microsoft.EntityFrameworkCore.SqlServer
Add a reference to the Domain Project (where we have defined our entities) and create a new Class in the DataAccess.EFCore Project and Name it ApplicationContext.cs.
public class ApplicationContext : DbContext { public ApplicationContext(DbContextOptions<ApplicationContext> options) : base(options) { } public DbSet<Developer> Developers { get; set; } public DbSet<Project> Projects { get; set; } }
Once our Data Access Layer is done, let's move to the WebApi Project to register EFCore within the ASP.NET Core Application. We will also update the database in this step to accomadate the Developer and Project Table.
Firstly, Install this package on the WebApi Project. This allows you to run EF Core commands on the CLI.
Install-Package Microsoft.EntityFrameworkCore.Tools
Next, Navigate to Startup.cs and add this line to Register the ApplicationContext class that we created. Note that you will have to add a refernce of the DataAccess.EFCore Project to the WebApi Project.
services.AddDbContext<ApplicationContext>(options => options.UseSqlServer( Configuration.GetConnectionString("DefaultConnection"), b => b.MigrationsAssembly(typeof(ApplicationContext).Assembly.FullName)));
After that, open up the appsettings.json file in the Api Project and add the connection string.
"ConnectionStrings": { "DefaultConnection": "<your connection string>", },
Finally, Let's update the database. Open your Package Manager Console on Visual Studio and run the following commands.
add-migration Initial update-database
Make sure that you have set your Startup Project as WebApi and the Default Project as DataAccess.EFCore. Here is a screenshot.
Ps, This is a very basic setup of Entity Framework Core. I have written a detailed Guide on Entity Framework Core – Code First Apporach. Give it a look to learn more.
Let's Keep Repositories Away for a Moment.
Now that we have configured our EFCore Layer, let's talk a bit about the traditional way to get data from this layer. Traditionally, you would directly call the dbContext object to read and write data. This is fine. But is it really ideal for the long run? When you use the dbContext directly, what you are doing is that, the Entity Framework Core is being tightly coupled within your application. So, Tommorow when there is something newer and better than EFCore, you would find it really annoying to implement the new tech and make the corresponding changes. Right?
One more disadvantage of directly using the dbContext directly is that you would be exposing the DbContext, which is totally insecure.
This is the reason to use Repository Pattern in ASP.NET Core Applications.
Practical Use-Case of Repositories
While Performing CRUD Operations with Entity Framework Core, you might have noticed that the basic essence of the code keeps the same. Yet we write it multiple times over and over. The CRUD Operations include Create, Read, Update, and Delete. So, why not have a class / interface setup where you can generalize each of these operations.
Building a Generic Repository
First up, let's add a new folder Interfaces in our Domain Project. Why? Because, we will be inverting the dependencies, so that, you can define the interface in the Domain Project, but the implementation can be outside the Domain Project. In this case, the implementations will go the DataAccess.EFCore Project. Thus, your domain layer will not depends on anything, rather, the other layers tend to depend on the Domain Layer's interface. This is a simple explanation of Dependency Inversion Principle. Pretty Cool, yeah?
Add a new interface, Interfaces/IGenericRepository.cs
public interface IGenericRepository<T> where T : class { T GetById(int id); IEnumerable<T> GetAll(); IEnumerable<T> Find(Expression<Func<T, bool>> expression); void Add(T entity); void AddRange(IEnumerable<T> entities); void Remove(T entity); void RemoveRange(IEnumerable<T> entities); }
This will be a Generic Interface, that can be used for both the Developer and Project Classes. Here T is the specific class.
The set of functions depends on your preference. Ideally, we require 7 functions that cover most of the data handling part.
- Get's the entity By Id.
- Get's all the Record.
- Finds a set of record that matches the passed expression.
- Adds a new record to the context
- Add a list of records
- Removes a record from the context
- Removes a list of records.
Now, Let's implement this Interfaces. Create a new class in the DataAccess.EFCore Project and name it Repositories/GenericRepository
public class GenericRepository<T> : IGenericRepository<T> where T : class { protected readonly ApplicationContext _context; public GenericRepository(ApplicationContext context) { _context = context; } public void Add(T entity) { _context.Set<T>().Add(entity); } public void AddRange(IEnumerable<T> entities) { _context.Set<T>().AddRange(entities); } public IEnumerable<T> Find(Expression<Func<T, bool>> expression) { return _context.Set<T>().Where(expression); } public IEnumerable<T> GetAll() { return _context.Set<T>().ToList(); } public T GetById(int id) { return _context.Set<T>().Find(id); } public void Remove(T entity) { _context.Set<T>().Remove(entity); } public void RemoveRange(IEnumerable<T> entities) { _context.Set<T>().RemoveRange(entities); } }
This class will implement the IGenericRepository Interface. We will also inject the ApplicationContext here. This way we are hiding all the actions related to the dbContext object within Repository Classes. Also note that, for the ADD and Remove Functions, we just do the operation on the dbContext object. But we are not yet commiting/updating/saving the changes to the database whatsover. This is not something to be done in a Repository Class. We would need Unit of Work Pattern for these cases where you commit data to the database. We will discuss about Unit of Work in a later section.
Understood why we used a Generic Repository instead of a IDevloperRepository?? When there are large number of entites in our application, we would need seperate repositories for each entities. But we do not want to implement all of the above 7 Functions in each and every Repository Class, right? Thus we made a generic repository that holds the most commonly used implementaions.
Now what happens if we need the records of Most Popular Developers from our Database? We do not have a function for it in our Generic Class, do we ? This is where we can see the advantage of building a Generic Repository.
Inheriting and Extending the Generic Repository
In the Domain Project, under the Interfaces, add a new interface named IDeveloperRepository.
public interface IDeveloperRepository : IGenericRepository<Developer> { IEnumerable<Developer> GetPopularDevelopers(int count); }
Here we are inheriting all the Functions of the Generic Repository, as well as adding a new Funciton 'GetPopularDevelopers'. Get it?
Let's implement the IDeveloperRepostory. Go to the DataAccess Project and under Repositories folder, add a new class, DeveloperRepository.
public class DeveloperRepository : GenericRepository<Developer>, IDeveloperRepository { public DeveloperRepository(ApplicationContext context):base(context) { } public IEnumerable<Developer> GetPopularDevelopers(int count) { return _context.Developers.OrderByDescending(d => d.Followers).Take(count).ToList(); } }
You can notice that we have not implemented all the 7 functions here, as it is is already implemented in our Generic Repository. Saves a lot of lines, yeah?
Similary, let's create interface and implementation for ProjectRepository.
public interface IProjectRepository : IGenericRepository<Project> { }
Now, the implementation.
public class ProjectRepository : GenericRepository<Project>, IProjectRepository { public ProjectRepository(ApplicationContext context): base(context) { } }
You can see that the interface and implementations are quite blank. So why create new class and interface for Project? This can also attribute to a good practice while developing applications. We also anticipate that in future, there can be functions that are spcific to the Project Entity. To support them later on, we provide with interfaces and classes. Future Proofing, yeah?
Finally, let's register these Interfaces to the respective implementaions in the Startup.cs of the WebApi Project. Navigate to Startup.cs/ConfigureServices Method and add these lines.
#region Repositories services.AddTransient(typeof(IGenericRepository<>), typeof(GenericRepository<>)); services.AddTransient<IDeveloperRepository, DeveloperRepository>(); services.AddTransient<IProjectRepository, ProjectRepository>();
0 Response to "How To Create A Blog In Asp.net Using C"
Post a Comment