Mastering API Development in .NET 9: A Complete Guide to Persistence, CRUD Operations, and Migrations
As modern web applications evolve, building robust APIs that can handle dynamic data and persist changes is crucial for success. In this guide, we'll dive into how to build APIs using .NET 9, integrate them with Entity Framework for data management, and handle CRUD operations efficiently. Whether you're a beginner or an intermediate developer, this step-by-step tutorial will help you understand everything from setting up your API to performing migrations and handling database persistence.
Step 1: Setting Up .NET 9 and API Essentials
When working with .NET 9 APIs, it's essential to set up the project and configure key components.
No Swagger Support in .NET 9: Unlike some previous versions, .NET 9 does not come with Swagger support out-of-the-box. However, you can easily add it via NuGet packages like
Swashbuckle.AspNetCore
for API documentation.Using
appsettings.json
for Configuration: Theappsettings.json
file is the go-to place for storing connection strings. Here’s how you can configure it for your SQL Server connection:jsonCopy code{ "ConnectionStrings": { "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=VideoGameDb;Trusted_Connection=True;" } }
Step 2: OpenAPI Integration
OpenAPI (formerly known as Swagger) helps in testing and exploring your API endpoints. To use OpenAPI, simply visit the /openapi/v1.json
endpoint:
For example:
bashCopy codehttps://localhost:7026/openapi/v1.json
Step 3: Setting Up Entity Framework and Database Connection
To use Entity Framework (EF) with .NET 9, you'll need to set up a DbContext
class. There are two main approaches for data models:
Code-First: You define your models in code, and the database schema is generated from them.
Database-First: You start with an existing database, and EF generates the models based on it.
To configure your database connection:
Install the necessary packages:
Microsoft.EntityFrameworkCore.SqlServer
Add the DbContext to the
Program.cs
orStartup.cs
file:csharpCopy codebuilder.Services.AddDbContext<VideoGameDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
Step 4: Performing Migrations
Migrations help you update the database schema as your model evolves. Here’s how you can create and apply migrations using the Package Manager Console:
Add a migration:
bashCopy codeAdd-Migration Initial
Apply the migration:
bashCopy codeUpdate-Database
Step 5: Seeding Initial Data
Once you’ve set up your models and migrations, you’ll likely want to seed some initial data into your database. To do this, you can use the OnModelCreating
method in your DbContext
class.
Example of seeding data:
csharpCopy codeprotected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<VideoGame>().HasData(
new VideoGame { Id = 1, Title = "Test Game", Platform = "PC", Developer = "Dev", Publisher = "Pub" },
new VideoGame { Id = 2, Title = "Another Game", Platform = "Xbox", Developer = "Dev2", Publisher = "Pub2" }
);
}
Step 6: CRUD Operations in the Controller
With the database connection and migrations set up, it’s time to build out the CRUD (Create, Read, Update, Delete) operations in the controller.
Create: Adds a new game to the database.
Read: Retrieves games based on criteria (all games or by ID).
Update: Modifies an existing game.
Delete: Removes a game from the database.
Each of these actions should be asynchronous for better performance, as database operations can take time.
csharpCopy codepublic async Task<IActionResult> AddVideoGame(VideoGame game)
{
_context.VideoGames.Add(game);
await _context.SaveChangesAsync();
return CreatedAtAction(nameof(GetVideoGameById), new { id = game.Id }, game);
}
Step 7: Finalizing with Testing
Before deploying your API, make sure to write unit tests to ensure everything is working correctly. Use tools like xUnit to test CRUD operations and edge cases (e.g., testing if non-existing games return a NotFoundResult
).
Here’s a sample test for deleting a video game:
csharpCopy code[Fact]
public async Task DeleteVideoGame_ReturnsNoContent_WhenGameExists()
{
var result = await _controller.DeleteVideoGame(1); // Existing ID
Assert.IsType<NoContentResult>(result.Result);
}
Conclusion
By following these steps, you'll be able to build powerful and scalable APIs using .NET 9 and Entity Framework. Whether you’re creating a small project or a large-scale application, the principles of using persistence, migrations, and dynamic CRUD operations remain crucial.
With this knowledge, you should be well on your way to mastering API development in .NET 9, handling everything from database connections to data migrations and testing.