loading...
Cover image for .Net Core REST API Tutorial: Creating the foundations.

.Net Core REST API Tutorial: Creating the foundations.

otamnitram profile image Martín Mato ・4 min read

.Net Core REST API Tutorial (2 Part Series)

1) .Net Core REST API Tutorial: Introduction 2) .Net Core REST API Tutorial: Creating the foundations.

Previous post

What do we want to accomplish?

In the previous chapter we saw how to configure our IDE and create a new blank solution with an API project.

The idea in this post is to complete the structure of our app creating the foundations of our app to add functionality later.

There will be things missing in this chapter which more experienced devs may find out, but we will add them later. We want this to be simple so we can learn how to do it.

With every said, let’s code and add our layers.

Project Structure

We will structure this as a typical 3-layer architecture, but with some enhancements:

  • API: Is the project where our controllers will be. The point of access to our app.
  • Core: Is the foundation library where we will have all the models, definitions and contracts shared across all layers.
  • Services: Our business layer
  • Data: Better known as DAL (Data access layer) is to access the data. We use ORM Entity Framework Core with code first and migration patterns.

We created API layer in the last chapter, so we need to create the other 3 libraries and add them to the solution:

dotnet new classlib -o cook-webapi.Core 
dotnet sln add cook-webapi.Core 
dotnet new classlib -o cook-webapi.Services 
dotnet sln add cook-webapi.Services 
dotnet new classlib -o cook-webapi.Data 
dotnet sln add cook-webapi.Data 

Last, we need to add dependencies:

dotnet add cook-webapi.Data reference cook-webapi.Core 
dotnet add cook-webapi.Services reference cook-webapi.Core 
dotnet add cook-webapi.Api reference cook-webapi.Services cook-webapi.Core cook-webapi.Data 

Adding the foundations

After adding all the layers and dependencies, we need to work on the foundations of our app.

Models

As this is a cooking app we will need Recipes and Chefs. Let’s create a folder called Models in the Core layer and add them:

Recipe model should look like this:

using System.Collections.ObjectModel; 
using System.Collections.Generic; 
namespace cook_webapi.Core.Models 
{ 
  public class Recipe 
  { 
    public Recipe() 
    { 
      Chef = new Chef(); 
    } 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public List<string> Steps { get; set; } 
    public Chef Chef { get; set; } 
  } 
} 

Then, we add the Chef model:

using System.Collections.ObjectModel; 
using System.Collections.Generic; 
namespace cook_webapi.Core.Models 
{ 
  public class Chef 
  { 
    public Chef() 
    { 
      Recipes = new Collection<Recipe>(); 
    } 
    public int id { get; set; } 
    public string Name { get; set; } 
    public ICollection<Recipe> Recipes { get; set; } 
  } 
} 

Repository

In order to keep concerns separated, improve reusability and testability we will use a repository pattern. This mean we want to decouple our database code and keep it separated.

Also we want to add the concept of Unit Of Work to handle or changes like transactions and the save them.

Having a generic repository is useful too to have all the basic operations in one place and don’t have to repeat code.

In the Core library we are creating structure contracts, so we can do this using interfaces.

Generic repository:

using System; 
using System.Collections.Generic; 
using System.Linq.Expressions; 
using System.Threading.Tasks; 
namespace cook_webapi.Core.Repositories 
{ 
  public interface IRepository<TEntity> where TEntity : class 
  { 
    Task<TEntity> GetByIdAsync(int id); 
    Task<IEnumerable<TEntity>> GetAllAsync(); 
    IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> query); 
    Task<TEntity> SingleOrDefaultAsync(Expression<Func<TEntity, bool>> query); 
    Task AddAsync(TEntity entity); 
    Task AddRangeAsync(IEnumerable<TEntity> entities); 
    void Remove(TEntity entity); 
    void RemoveRange(IEnumerable<TEntity> entities); 
    void Update(TEntity entity); 
  } 
} 

Then we need add repositories to handle specific operations for each model:

using System.Collections.Generic; 
using System.Threading.Tasks; 
using cook_webapi.Core.Models; 
namespace cook_webapi.Core.Repositories 
{ 
    public interface IChefRepository : IRepository<Chef> 
    { 
        Task<IEnumerable<Chef>> GetWithRecipesAsync(); 
    } 
} 
using System.Collections.Generic; 
using System.Threading.Tasks; 
using cook_webapi.Core.Models; 
namespace cook_webapi.Core.Repositories 
{ 
    public interface IRecipeRepository : IRepository<Recipe> 
    { 
        Task<IEnumerable<Recipe>> GetAllWithChef(); 
    } 
} 

Also, we need the contract for our Unit Of Work, we can place this in the root folder of our Core library:

using System.Threading.Tasks; 
using cook_webapi.Core.Repositories; 
namespace cook_webapi.Core 
{ 
    public interface IUnitOfWork 
    { 
        IChefRepository Chefs { get; } 
        IRecipeRepository Recipes { get; } 
        Task<int> SaveChangesAsync(); 
    } 
} 

Services

We have added our contracts for the data layer now we need to do the same with the service layer. For that we create the service folder in the Core library and add services for recipes and chefs.

We need to add only the operations we will use later in the controllers.

IChefService

using System.Collections.Generic; 
using System.Threading.Tasks; 
using cook_webapi.Core.Models; 
namespace cook_webapi.Core.Services 
{ 
    public interface IChefService 
    { 
        Task<IEnumerable<Chef>> GetAllWithRecipes(); 
        Task<Chef> GetChefById(int id); 
        Task<Chef> CreateChef(Chef chef); 
        Task UpdateChef(Chef chefToBeUpdated, Chef chef); 
        Task DeleteChef(Chef chef); 
    } 
} 

IRecipeService

using System.Collections.Generic; 
using System.Threading.Tasks; 
using cook_webapi.Core.Models; 
namespace cook_webapi.Core.Services 
{ 
    public interface IRecipeService 
    { 
        Task<IEnumerable<Recipe>> GetAllWithChef(); 
        Task<Recipe> GetRecipeById(); 
        Task UpdateRecipe(Recipe recipeToBeUpdated, Recipe recipe); 
        Task DeleteRecipe(Recipe recipe); 
    } 
} 

What’s next?

Now we have all the foundation of our app ready. Next we will need to code our data layer, install Entity Framework and create our first migrations.

Links

Summing Up

We learnt how to create multiple layers. Also, the models and contracts which are the foundations of the entire webapi.

In Next post we will install Entity Framework, learn how to manipulate and get the data and create migrations.

Follow me to receive updates on next chapter, I will upload it in a few days.

.Net Core REST API Tutorial (2 Part Series)

1) .Net Core REST API Tutorial: Introduction 2) .Net Core REST API Tutorial: Creating the foundations.

Posted on May 29 by:

otamnitram profile

Martín Mato

@otamnitram

Martin Mato is a self-taught developer who lives and works in Uruguay. Learning and developing for the last 10 years with #react #react-native #angular #dotnet

Discussion

markdown guide
 

You don't need UoW and repository pattern with EF Core because it is already implemented.

 

Even though EF Core implements it, I think is a good practice to decouple our project. In this way it does not bound you to a particular ORM or EF Core version. Also, is better in this way for mocking to test.