Repository Pattern Implementation in ASP.NET Core

osempu

Oscar Montenegro

Posted on March 29, 2023

Repository Pattern Implementation in ASP.NET Core

Hello guys, this is the fourth part of a series where we are building a web API using ASP NET Core 7.0. In the previous post, we saw how to add some basic logging to our app to give us useful insight whenever an endpoint from our API was called, today we will talk about an essential design pattern in software development and that is the โ€œRepository Patternโ€.

The repository pattern is a design pattern that is commonly used in software development to separate the business logic from the data access logic. This pattern provides an abstraction layer between the data access layer and the business logic layer.

What is the Repository Pattern โ“

The repository pattern is a design pattern that provides an abstraction layer between the data access layer and the business logic layer. It defines a set of interfaces for data access, and the implementation of these interfaces is handled by the data access layer. The repository pattern makes it easier to test the business logic layer, as it can be tested in isolation from the data access layer.

Why is it Useful ๐Ÿ‘๐Ÿพ

The repository pattern is useful for several reasons. Firstly, it makes it easier to maintain the codebase, as it separates the concerns of the business logic and data access layers. Secondly, it provides a clean separation of concerns, making it easier to test the business logic layer. Finally, it reduces code duplication, as all data access-related code can be written once and reused across the application.

Clone the repo to follow along ๐Ÿ™

If you desire to follow along with the tutorial you can clone the repository on GitHub. Download the โ€œSerilogLoggingโ€ branch which contains the latest changes up to this point.

GitHub - Osempu/BlogAPI at SerilogLogging

Implementing the Repository pattern into our Web API ๐Ÿ•ธ๏ธ

Letโ€™s start implementing the repository pattern by adding a folder inside our Data folder called Repositories and inside it, we will create an interface named IPostRepositoryPattern this will be our repository interface for our posts.

The Repository interface ๐Ÿ’ป

public interface IPostRepository 
{
    IEnumerable<Post> GetPost();
    Post GetPost(int id);
    void Add(Post post);
    void Edit(Post post);
    void Delete(int id);
}
Enter fullscreen mode Exit fullscreen mode

On this interface, we define the CRUD methods that we need to interact with the data that is stored in our database, interfaces donโ€™t define any implementation that is that there is no code inside of them because we do that on the actual repository class which we will be coding right now.

The repository class ๐Ÿ›๏ธ

public class PostRepository : IPostRepository
{
    private readonly BlogDbContext context;

    public PostRepository(BlogDbContext context)
    {
        this.context = context;
    }

    public void Add(Post post)
    {
        context.Add(post);
        context.SaveChanges();
    }

    public void Delete(int id)
    {
        var post = context.Posts.Find(id);
        context.Remove(post);
        context.SaveChanges();
    }

    public void Edit(Post post)
    {
        context.Entry(post).State = EntityState.Modified;
        context.SaveChanges();
    }

    public IEnumerable<Post> GetPost()
    {
        var allPosts = context.Posts.ToList();
        return allPosts;
    }

    public Post GetPost(int id)
    {
        var post = context.Posts.Find(id);
        return post;
    }
}
Enter fullscreen mode Exit fullscreen mode

This is the repository class where we actually have the implementation to communicate with the database using the BlogDbContext class. The repository class *********************************************************************************************must implement the repository interface********************************************************************************************* in order for the repository pattern to work and then and only then we can code the implementation.

Inject the BlogDbContext via Dependency Injection ๐Ÿ’‰

Before adding any code first we need to create a constructor and pass the BlogDbContext as a parameter and then initialize a BlogDbContext readonly field.

private readonly BlogDbContext context;

public PostRepository(BlogDbContext context)
{
    this.context = context;
}
Enter fullscreen mode Exit fullscreen mode

Edit method

All the methods are basically the same as we had them on the controller class except to the Edit method in which we donโ€™t need to pass the postId as a parameter neither we need to look for it to update it.

public void Edit(Post post)
{
    context.Entry(post).State = EntityState.Modified;
    context.SaveChanges();
}
Enter fullscreen mode Exit fullscreen mode

Here we only need to pass the Post as a parameter and then we notify entity framework that the state of the post is modified so it starts to track the changes and after that, we can save the changes.

Modifying the PostsController class โš’๏ธ

Now with our brand new repository class ready we need to use it in our controller class.

[ApiController]
[Route("api/post")]
public class PostsController : ControllerBase
{
    private readonly ILogger<PostsController> logger;
    private readonly IPostRepository repository;

    public PostsController(IPostRepository repository, ILogger<PostsController> logger)
    {
        this.logger = logger;
        this.repository = repository;
    }

    [HttpGet]
    public IActionResult GetPost()
    {
        var posts = repository.GetPost();
        logger.LogDebug($"Get method called, got {posts.Count()} results");
        return Ok(posts);
    }

    [HttpGet("{id:int}")]
    public IActionResult GetPost(int id)
    {
        try
        {
            var post = repository.GetPost(id);
            return Ok(post);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, $"Error getting post with id {id}");
            throw;
        }
    }

    [HttpPost]
    public IActionResult CreatePost(Post post)
    {
        try
        {
            repository.Add(post);
            return CreatedAtAction(nameof(GetPost), new { id = post.Id }, null);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Unexpected error on Post method");
            throw;
        }
    }

    [HttpPut]
    public IActionResult EditPost([FromBody] Post post)
    {
        repository.Edit(post);
        return NoContent();
    }

    [HttpDelete("{id:int}")]
    public IActionResult DeletePost(int id)
    {
        try
        {
            repository.Delete(id);

            return NoContent();
        }
        catch (Exception ex)
        {
            logger.LogError(ex, $"Unexpected error on Delete method trying to delete post with Id {id}");
            throw;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Again we will inject the IPostRepository interface via dependency injection in the controller constructor to be able to use it.

The code remains almost the same for all of the CRUD endpoints in fact now the code is a little bit more slim and readable thanks to the repository pattern but there is one exception and that is the EditPost method.

The EditPost method now only needs the Post as a parameter with the [FromBody] tag and inside we only make the call to the edit method from the repository we no longer need to look for the post to update or to manually manipulate the properties of the post to update it, we simply need to pass the post to the edit method and that would be all, that is a great improvement for our code.

Register the Repository as a service ๐Ÿ•โ€๐Ÿฆบ

The last part of the puzzle is to register our repository interface and class in the Program class so it can work the expected way. Add this line of code below the services.AddControllers(); line.

builder.Services.AddTransient<IPostRepository, PostRepository>();
Enter fullscreen mode Exit fullscreen mode

Test the API ๐Ÿงช

Now you should be able to test the API and it should work the same as before but if you debug the application you will see how the API calls the Repository class and then it communicates to the database through the BlogDbContext.

Conclusion ๐ŸŒ‡

Using the repository pattern helps us to separate the data access layer from the logic in our controller class(separation of concerns) and also helps us to avoid code duplication in the future if we need to call the blogs from another controller we can make use of the existing repository.

Follow me! ๐Ÿšถ๐Ÿพ

If you enjoyed this article remember to follow me on my blog Unit Coding where I post at least twice a week about web API development, fun projects with blazor, and other C# and .NET tips and tricks of all kinds, thanks for your time and I hope you have a happy coding!

๐Ÿ’– ๐Ÿ’ช ๐Ÿ™… ๐Ÿšฉ
osempu
Oscar Montenegro

Posted on March 29, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

ยฉ TheLazy.dev

About