Photo by Tobias Fischer on Unsplash
Modeling Users and Posts with C# and Entity Framework Core in ASP.NET Core Web API
Introduction
Creating a RESTful API with ASP.NET Core is a popular choice among developers who work with C#. In this tutorial, we will walk through modeling two entities—users and Posts—using Entity Framework Core (EF Core) and then expose them via a REST API.
Prerequisites
.NET SDK installed
A text editor or IDE of your choice
Basic knowledge of C#, REST, and Entity Framework
Setting Up Your Project
First, create a new ASP.NET Core Web API project:
dotnet new webapi -n UserPostApi
Add the EF Core package for SQL Server:
cd UserPostApi
dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.EntityFrameworkCore.Sqlite
Creating Models
We'll start by defining our User
and Post
models. Create a folder named. Models
And add two classes: User.cs
and Post.cs
.
User.cs
public class User
{
public int UserId { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public List<Post> Posts { get; set; }
}
Post.cs
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int UserId { get; set; }
public User User { get; set; }
}
Configuring DbContext
Create a new file AppDbContext.cs
:
using Microsoft.EntityFrameworkCore;
public class AppDbContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Data Source=app.db"));
}
}
Creating Controllers
Generate API controllers for your models.
UsersController.cs
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
private readonly AppDbContext _context;
public UsersController(AppDbContext context)
{
_context = context;
}
[HttpGet]
public ActionResult<List<User>> GetAll()
{
return _context.Users.ToList();
}
// Add this method to handle POST requests for creating a new user
[HttpPost]
public async Task<ActionResult<User>> Create(User user)
{
_context.Users.Add(user);
await _context.SaveChangesAsync();
return CreatedAtAction(nameof(GetById), new { id = user.Id }, user);
}
// Optionally add this method to retrieve a single user by ID
[HttpGet("{id}")]
public ActionResult<User> GetById(int id)
{
var user = _context.Users.FirstOrDefault(u => u.Id == id);
if (user == null)
{
return NotFound();
}
return user;
}
// ... more CRUD operations
}
PostsController.cs
[ApiController]
[Route("api/[controller]")]
public class PostsController : ControllerBase
{
private readonly AppDbContext _context;
public PostsController(AppDbContext context)
{
_context = context;
}
[HttpGet]
public ActionResult<List<Post>> GetAll()
{
return _context.Posts.ToList();
}
// Add this method to handle POST requests
[HttpPost]
public async Task<ActionResult<Post>> Create(Post post)
{
_context.Posts.Add(post);
await _context.SaveChangesAsync();
return CreatedAtAction(nameof(GetById), new { id = post.Id }, post);
}
// Optionally add this method to retrieve a single post by ID
[HttpGet("{id}")]
public ActionResult<Post> GetById(int id)
{
var post = _context.Posts.FirstOrDefault(p => p.Id == id);
if (post == null)
{
return NotFound();
}
return post;
}
// ... more CRUD operations
}
Understanding Primary and Foreign Keys
EF Core identifies primary keys and foreign keys through conventions, data annotations, or Fluent API configurations.
For example, by convention:
UserId
in theUser
class is considered a primary key.UserId
in thePost
class is regarded as a foreign key.
You can also explicitly set these keys using Data Annotations or Fluent API.
Testing the API
Run your API and use Postman or a similar tool to test the endpoints:
dotnet ef migrations add initial
dotnet ef database update
Test Endpoints
Summary
We built a simple REST API using ASP.NET Core, modeled our Users and Posts entities, and configured the database context using Entity Framework Core. This example is a foundational step to building more complex and feature-rich APIs.
Happy Hacking 🏗️