Asp.Net Web Api Using Repositories And Service Layers Complete Guide

 Last Update:2025-06-23T00:00:00     .NET School AI Teacher - SELECT ANY TEXT TO EXPLANATION.    10 mins read      Difficulty-Level: beginner

Understanding the Core Concepts of ASP.NET Web API Using Repositories and Service Layers

ASP.NET Web API Using Repositories and Service Layers

Importance of Repositories

A repository is essentially an abstraction layer that sits between the data source and the business logic. It simplifies access to data and helps manage data-related concerns. Here's why repositories are important:

  1. Abstraction: Repositories provide an abstraction over the data access methods. This means that the way data is fetched, updated, or deleted is hidden behind a consistent interface.
  2. Testability: By using repositories, you can easily swap out the real data access logic with mock implementations. This makes unit testing straightforward.
  3. Consistency: Repositories ensure consistency in how data operations are performed across different parts of an application.

Repository Pattern

In ASP.NET, the repository pattern is typically implemented using an interface and a concrete class.

  1. Interface:

    public interface IRepository<T>
    {
        IEnumerable<T> GetAll();
        T GetById(int id);
        void Add(T entity);
        void Update(T entity);
        void Delete(T entity);
    }
    
  2. Concrete Class:

    public class Repository<T> : IRepository<T> where T : class
    {
        private readonly DbContext _context;
        private DbSet<T> _entities;
    
        public Repository(DbContext context)
        {
            _context = context;
        }
    
        protected virtual DbSet<T> Entities
        {
            get
            {
                return _entities ?? (_entities = _context.Set<T>());
            }
        }
    
        public virtual IEnumerable<T> GetAll()
        {
            return Entities.ToList();
        }
    
        public virtual T GetById(int id)
        {
            return Entities.Find(id);
        }
    
        public virtual void Add(T entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException(nameof(entity));
            }
    
            Entities.Add(entity);
            _context.SaveChanges();
        }
    
        public virtual void Update(T entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException(nameof(entity));
            }
    
            Entities.Update(entity);
            _context.SaveChanges();
        }
    
        public virtual void Delete(T entity)
        {
            if (entity == null)
            {
                throw new ArgumentNullException(nameof(entity));
            }
    
            Entities.Remove(entity);
            _context.SaveChanges();
        }
    }
    

Importance of Service Layers

The service layer acts as an intermediary between the Web API controllers and the repositories. It encapsulates business logic and can also interact with other service layers, if needed.

  1. Business Logic: Service layers are responsible for implementing business rules and processing data before passing it to the repository for storage.
  2. Separation of Concerns: This pattern helps separate the web API's concerns (like handling HTTP requests) from the business logic and data access logic.
  3. Reusability: Business logic can be reused across different parts of the application or even across different applications, just by reusing the service layer.

Service Layer Example

  1. Interface:

    public interface IEmployeeService
    {
        IEnumerable<Employee> GetAllEmployees();
        Employee GetEmployeeById(int id);
        void AddEmployee(Employee employee);
        void UpdateEmployee(Employee employee);
        void DeleteEmployee(int id);
    }
    
  2. Concrete Class:

    public class EmployeeService : IEmployeeService
    {
        private readonly IRepository<Employee> _employeeRepository;
    
        public EmployeeService(IRepository<Employee> employeeRepository)
        {
            _employeeRepository = employeeRepository;
        }
    
        public IEnumerable<Employee> GetAllEmployees()
        {
            return _employeeRepository.GetAll();
        }
    
        public Employee GetEmployeeById(int id)
        {
            return _employeeRepository.GetById(id);
        }
    
        public void AddEmployee(Employee employee)
        {
            _employeeRepository.Add(employee);
        }
    
        public void UpdateEmployee(Employee employee)
        {
            _employeeRepository.Update(employee);
        }
    
        public void DeleteEmployee(int id)
        {
            var employee = _employeeRepository.GetById(id);
            if (employee != null)
            {
                _employeeRepository.Delete(employee);
            }
        }
    }
    

Web API Controllers

Finally, the Web API controllers consume the service layers to handle incoming HTTP requests and return appropriate responses.

  1. Controller Example:

Online Code run

🔔 Note: Select your programming language to check or run code at

💻 Run Code Compiler

Step-by-Step Guide: How to Implement ASP.NET Web API Using Repositories and Service Layers

Step 1: Create a New ASP.NET Web API Project

  1. Open Visual Studio.

  2. Create a New Project:

    • Go to File > New > Project.
    • Choose ASP.NET Core Web App (API).
    • Provide a name for the project, e.g., BookStoreApi.
    • Click Create.
  3. Select Framework:

    • Ensure you're selecting the appropriate .NET version (e.g., .NET 6 or later).
    • Click Create.
  4. Configure the Project:

    • Leave default settings unless you want minimal changes.
    • Click Create.

Step 2: Define Models

Let's start by creating a model for our books.

  1. Add a Model Folder:

    • Right-click on your project in Solution Explorer.
    • Select Add > New Folder.
    • Name it Models.
  2. Add Book Model:

    • Right-click on Models folder.
    • Select Add > Class.
    • Name it Book.cs.
namespace BookStoreApi.Models
{
    public class Book
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string Author { get; set; }
        public decimal Price { get; set; }
        public DateTime PublishDate { get; set; }
    }
}

Step 3: Set Up Data Access Layer (Repository Pattern)

The repository pattern abstracts data access logic and provides a way to interact with our data source.

  1. Add a Repository Interface:
    • Right-click on your project.

    • Select Add > New Folder.

    • Name it Repositories.

    • Inside Repositories, right-click and select Add > Interface.

    • Name it IBookRepository.cs.

using System.Collections.Generic;
using System.Threading.Tasks;
using BookStoreApi.Models;

namespace BookStoreApi.Repositories
{
    public interface IBookRepository
    {
        Task<IEnumerable<Book>> GetAllBooksAsync();
        Task<Book> GetBookByIdAsync(int id);
        Task AddBookAsync(Book book);
        Task UpdateBookAsync(Book book);
        Task DeleteBookAsync(int id);
    }
}
  1. Add a Concrete Repository Class:

    • Inside Repositories, right-click and select Add > Class.

    • Name it BookRepository.cs.

    • This example will use an in-memory collection for simplicity, but you can integrate it with a real database like Entity Framework Core easily.

using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using BookStoreApi.Models;

namespace BookStoreApi.Repositories
{
    public class BookRepository : IBookRepository
    {
        private static ConcurrentDictionary<int, Book> _books = 
            new ConcurrentDictionary<int, Book>();

        static BookRepository()
        {
            // Adding some initial data
            _books.TryAdd(1, new Book 
            { 
                Id = 1, 
                Title = "1984", 
                Author = "George Orwell", 
                Price = 9.99m, 
                PublishDate = new DateTime(1949, 6, 8) 
            });
            _books.TryAdd(2, new Book 
            { 
               Id = 2, 
               Title = "To Kill a Mockingbird", 
               Author = "Harper Lee", 
               Price = 10.99m, 
               PublishDate = new DateTime(1960, 7, 11) 
            });
            _books.TryAdd(3, new Book 
            { 
                Id = 3, 
                Title = "The Great Gatsby", 
                Author = "F. Scott Fitzgerald", 
                Price = 8.99m, 
                PublishDate = new DateTime(1925, 4, 10) 
            });
        }

        public async Task<IEnumerable<Book>> GetAllBooksAsync()
        {
            await Task.Delay(1); // Simulating async call
            return _books.Values;
        }

        public async Task<Book> GetBookByIdAsync(int id)
        {
            await Task.Delay(1); // Simulating async call
            _books.TryGetValue(id, out var book);
            return book;
        }

        public async Task AddBookAsync(Book book)
        {
            await Task.Delay(1); // Simulating async call
            book.Id = _books.Keys.Max() + 1;
            _books.TryAdd(book.Id, book);
        }

        public async Task UpdateBookAsync(Book book)
        {
            await Task.Delay(1); // Simulating async call
            if (_books.ContainsKey(book.Id))
            {
                _books[book.Id] = book;
            }
        }

        public async Task DeleteBookAsync(int id)
        {
            await Task.Delay(1); // Simulating async call
            _books.TryRemove(id, out _);
        }
    }
}

Step 4: Implement the Service Layer

The service layer contains business logic and interacts with the repository layer.

  1. Add a Service Interfaces:
    • Right-click on your project.

    • Select Add > New Folder.

    • Name it Services.

    • Inside Services, right-click and select Add > Interface.

    • Name it IBookService.cs.

using System.Collections.Generic;
using System.Threading.Tasks;
using BookStoreApi.Models;

namespace BookStoreApi.Services
{
    public interface IBookService
    {
        Task<IEnumerable<Book>> GetAllBooksAsync();
        Task<Book> GetBookByIdAsync(int id);
        Task AddBookAsync(Book book);
        Task UpdateBookAsync(Book book);
        Task DeleteBookAsync(int id);
    }
}
  1. Add a Concrete Service Class:

    • Inside Services, right-click and select Add > Class.
    • Name it BookService.cs.
using System.Collections.Generic;
using System.Threading.Tasks;
using BookStoreApi.Models;
using BookStoreApi.Repositories;

namespace BookStoreApi.Services
{
    public class BookService : IBookService
    {
        private readonly IBookRepository _bookRepository;

        public BookService(IBookRepository bookRepository)
        {
            _bookRepository = bookRepository;
        }

        public async Task<IEnumerable<Book>> GetAllBooksAsync()
        {
            return await _bookRepository.GetAllBooksAsync();
        }

        public async Task<Book> GetBookByIdAsync(int id)
        {
            return await _bookRepository.GetBookByIdAsync(id);
        }

        public async Task AddBookAsync(Book book)
        {
            await _bookRepository.AddBookAsync(book);
        }

        public async Task UpdateBookAsync(Book book)
        {
            await _bookRepository.UpdateBookAsync(book);
        }

        public async Task DeleteBookAsync(int id)
        {
            await _bookRepository.DeleteBookAsync(id);
        }
    }
}

Step 5: Register Services in Dependency Injection Container

Register the repository and service classes in the DI container so that they can be injected into controllers.

  1. Open Program.cs in the project root.
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();

// Add repository and services as transient services
builder.Services.AddTransient<IBookRepository, BookRepository>();
builder.Services.AddTransient<IBookService, BookService>();

// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Step 6: Create a Controller

The controller handles HTTP requests and uses the service layer to perform operations.

  1. Add a Controllers Folder:

    • The Controllers folder is usually created by default, but in case not, you can add it manually:
      • Right-click on your project.
      • Select Add > New Folder.
      • Name it Controllers.
  2. Add a BookController Class:

    • Inside Controllers, right-click and select Add > Controller.

    • Choose API Controller - Empty.

    • Name it BooksController.cs.

using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading.Tasks;
using BookStoreApi.Models;
using BookStoreApi.Services;

namespace BookStoreApi.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class BooksController : ControllerBase
    {
        private readonly IBookService _bookService;

        public BooksController(IBookService bookService)
        {
            _bookService = bookService;
        }

        // GET: api/books
        [HttpGet]
        public async Task<ActionResult<IEnumerable<Book>>> GetBooks()
        {
            var books = await _bookService.GetAllBooksAsync();

            if (books == null || !books.Any())
            {
                return NotFound();
            }

            return Ok(books);
        }

        // GET: api/books/5
        [HttpGet("{id}")]
        public async Task<ActionResult<Book>> GetBook(int id)
        {
            var book = await _bookService.GetBookByIdAsync(id);

            if (book == null)
            {
                return NotFound();
            }

            return Ok(book);
        }

        // POST: api/books
        [HttpPost]
        public async Task<ActionResult<Book>> PostBook(Book book)
        {
            if (book == null)
            {
                return BadRequest();
            }

            await _bookService.AddBookAsync(book);
            return CreatedAtAction(nameof(GetBook), new { id = book.Id }, book);
        }

        // PUT: api/books/5
        [HttpPut("{id}")]
        public async Task<IActionResult> PutBook(int id, Book book)
        {
            if (id != book.Id)
            {
                return BadRequest();
            }

            var existingBook = await _bookService.GetBookByIdAsync(id);

            if (existingBook == null)
            {
                return NotFound();
            }

            await _bookService.UpdateBookAsync(book);
            return NoContent();
        }

        // DELETE: api/books/5
        [HttpDelete("{id}")]
        public async Task<IActionResult> DeleteBook(int id)
        {
            var book = await _bookService.GetBookByIdAsync(id);

            if (book == null)
            {
                return NotFound();
            }

            await _bookService.DeleteBookAsync(id);
            return NoContent();
        }
    }
}

Step 7: Test Your API

  1. Run the Application:

    • Press F5 to run the application.
    • It should automatically open the Swagger UI, where you can interact with your API.
  2. Perform CRUD Operations:

    • You can add, retrieve, update, and delete book records through the provided endpoints in Swagger UI.

Example API Endpoints:

  • GET /api/books: Get all books
  • GET /api/books/{id}: Get a specific book by ID
  • POST /api/books: Add a new book
  • PUT /api/books/{id}: Update an existing book by ID
  • DELETE /api/books/{id}: Delete a book by ID

Sample POST Request:

  • Endpoint: POST /api/books
  • Body: {"Title": "Brave New World", "Author": "Aldous Huxley", "Price": 7.99, "PublishDate": "1932-05-01"}

Sample Response:

{
  "id": 4,
  "title": "Brave New World",
  "author": "Aldous Huxley",
  "price": 7.99,
  "publishDate": "2024-04-16T00:00:00Z"
}

Conclusion

Following these steps, you have created a basic ASP.NET Web API using the repository and service layer patterns. This architecture ensures that your codebase is modular, testable, and scalable, making it easier to work on large projects and adding new features over time.

While this example used an in-memory store for simplicity, you can seamlessly integrate Entity Framework Core for database interactions following similar principles. Each layer (controller, service, and repository) remains decoupled from each other, enhancing the maintainability and flexibility of your application.

Top 10 Interview Questions & Answers on ASP.NET Web API Using Repositories and Service Layers

Top 10 Questions and Answers on ASP.NET Web API Using Repositories and Service Layers

1. What are the benefits of using Repositories in ASP.NET Web API?

  • Abstraction: Repositories abstract data access logic from the business logic, allowing the application to be more maintainable and testable.
  • Testability: It makes unit testing easier as dependencies can be mocked.
  • Maintainability: Changes in data access logic are localized, minimizing the impact on the rest of the application.
  • Consistency: Enforces a consistent pattern for data operations across the application.

2. How can you implement a Repository Pattern in ASP.NET Web API?

Answer: To implement the Repository Pattern in ASP.NET Web API, follow these steps:

  • Create an Interface: Define an interface (e.g., IRepository<TEntity>) with methods you need (Add, Get, Update, Delete).

  • Implement the Interface: Create a class that implements this interface. Here's a simple example:

    public interface IRepository<TEntity>
    {
        IEnumerable<TEntity> GetAll();
        TEntity GetById(int id);
        void Add(TEntity entity);
        void Update(TEntity entity);
        void Delete(TEntity entity);
    }
    
    public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
    {
        private readonly DbContext _dbContext;
        private readonly DbSet<TEntity> _dbSet;
    
        public Repository(DbContext dbContext)
        {
            _dbContext = dbContext;
            _dbSet = dbContext.Set<TEntity>();
        }
    
        public IEnumerable<TEntity> GetAll() => _dbSet.ToList();
        public TEntity GetById(int id) => _dbSet.FirstOrDefault(e => EF.Property<int>(e, "Id") == id);
        public void Add(TEntity entity) => _dbSet.Add(entity);
        public void Update(TEntity entity) => _dbContext.Entry(entity).State = EntityState.Modified;
        public void Delete(TEntity entity) => _dbSet.Remove(entity);
    }
    
  • Use Dependency Injection: Register your repository in Startup.cs or Program.cs using DI.

3. Why should you use a Service Layer in ASP.NET Web API?

Answer: A Service Layer in ASP.NET Web API:

  • Business Rules: Facilitates business logic without being tightly coupled to the repository or UI.
  • Separation of Concerns: Helps keep the application architecture clean by separating concerns.
  • Reusability: Allows business logic to be reused easily across different parts of the application or different applications.

4. How do you create a Service Layer in ASP.NET Web API?

Answer: To create a Service Layer, follow these steps:

  • Create an Interface: Define an interface for your service methods.

    public interface IService<T>
    {
        IEnumerable<T> GetAll();
        T GetById(int id);
        void Add(T entity);
        void Update(T entity);
        void Delete(T entity);
    }
    
  • Implement the Interface: Create a class that implements this interface.

    public class Service<T> : IService<T> where T : class
    {
        private readonly IRepository<T> _repository;
    
        public Service(IRepository<T> repository)
        {
            _repository = repository;
        }
    
        public IEnumerable<T> GetAll() => _repository.GetAll();
        public T GetById(int id) => _repository.GetById(id);
        public void Add(T entity) => _repository.Add(entity);
        public void Update(T entity) => _repository.Update(entity);
        public void Delete(T entity) => _repository.Delete(entity);
    }
    
  • Register Services in DI: Add service registrations in the DI container in Startup.cs or Program.cs.

5. What is Dependency Injection in ASP.NET Web API and why is it important?

Answer: Dependency Injection (DI) in ASP.NET Web API is a design pattern that allows the application to manage dependencies between objects. It is important because:

  • Maintainability: Eases maintenance by decoupling components.
  • Testability: Easier to test because dependencies can be mocked.
  • Reusability: Facilitates code reuse.
  • Scalability: Supports the development of complex applications by managing object lifetimes.

6. How do you configure Dependency Injection in ASP.NET Web API?

Answer: Configure DI in ASP.NET Web API using the Startup.cs or Program.cs class:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // Add DbContext
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

        // Add Repositories
        services.AddScoped(typeof(IRepository<>), typeof(Repository<>));

        // Add Services
        services.AddScoped(typeof(IService<>), typeof(Service<>));

        services.AddControllers();
    }
}

7. How does the Service Layer interact with the Controller in ASP.NET Web API?

Answer: The Service Layer interacts with the Controller in ASP.NET Web API by handling business logic, while the Controller handles HTTP requests and responses. Here’s a simple example:

public class ItemsController : ControllerBase
{
    private readonly IService<Item> _service;

    public ItemsController(IService<Item> service)
    {
        _service = service;
    }

    [HttpGet]
    public ActionResult<IEnumerable<Item>> GetItems()
    {
        return Ok(_service.GetAll());
    }

    [HttpGet("{id}")]
    public ActionResult<Item> GetItem(int id)
    {
        var item = _service.GetById(id);
        if (item == null)
            return NotFound();
        return Ok(item);
    }
}

8. What are Unit Tests and why are they important when using Repositories and Service Layers?

Answer: Unit Tests are tests written to verify the functionality of individual units of source code, such as functions, methods, and procedures. They are crucial because:

  • Accuracy: Ensures that code works as expected.
  • Maintenance: Helps maintain code over time, especially in large applications.
  • Refactoring: Facilitates safe code refactoring.
  • Continuous Integration: Facilitates automated testing in CI pipelines.

9. How do you mock repositories in ASP.NET Web API for Unit Testing?

Answer: To mock repositories for unit testing in ASP.NET Web API, you can use mocking frameworks like Moq:

[TestFixture]
public class ServiceTests
{
    private IService<Item> _service;
    private Mock<IRepository<Item>> _mockRepo;

    [SetUp]
    public void Setup()
    {
        _mockRepo = new Mock<IRepository<Item>>();
        _service = new Service<Item>(_mockRepo.Object);
    }

    [Test]
    public void GetAll_Succeeds()
    {
        _mockRepo.Setup(repo => repo.GetAll()).Returns(new List<Item>());

        var result = _service.GetAll().ToList();

        Assert.IsNotNull(result);
        Assert.AreEqual(0, result.Count);
    }
}

10. What are the considerations when designing repositories and service layers in ASP.NET Web API?

Answer: When designing repositories and service layers in ASP.NET Web API, consider:

  • Scalability: Design for scalability and performance.
  • Security: Ensure operations are secure and follow best practices.
  • Error Handling: Implement robust error handling to manage exceptional scenarios.
  • Validation: Validate incoming data to prevent invalid operations.
  • Extensibility: Design with extensibility in mind to accommodate future changes.

You May Like This Related .NET Topic

Login to post a comment.