Development Environment: Visual Studio 2026
Target Framework: .NET Core 10
Database: SQL Server
ORM: Dapper
Example Domain: Automobile Industry (Vehicles)
Introduction: What is Dapper and Why Use It?
When building high-performance Web APIs in .NET Core 10, one key decision you’ll make is how your application communicates with the database.
You likely know Entity Framework Core (EF Core) — a powerful full-featured ORM. But sometimes, especially in enterprise-grade or high-performance systems, you want something:
Faster
Lightweight
More SQL-controlled
Less abstraction
That’s where Dapper comes in.
What is Dapper?
Dapper is a micro-ORM built by the Stack Overflow team. It extends IDbConnection and maps query results directly to C# objects with minimal overhead.
It doesn’t generate SQL for you.
It doesn’t track changes.
It doesn’t manage migrations.
It simply executes SQL efficiently and maps results.
Dapper vs Entity Framework
| Feature | Dapper | EF Core |
|---|
| Performance | Very Fast | Moderate |
| Abstraction | Minimal | High |
| SQL Control | Full Control | LINQ-based |
| Change Tracking | No | Yes |
| Best For | High-performance APIs | Complex business logic |
If you're building scalable APIs for business systems — like an Automobile Industry platform managing Manufacturers and Vehicles — Dapper gives you precision and performance.
Think of EF Core as an automatic car.
Dapper? A manual transmission sports car.
Step 1: Installing Dapper in Visual Studio 2026
Option 1: Using Package Manager Console
Open Visual Studio 2026
Go to:
Tools → NuGet Package Manager → Package Manager Console
Run:
Install-Package Dapper
Option 2: Using NuGet GUI
Right-click your project
Select Manage NuGet Packages
Search for Dapper
Click Install
That’s it. Dapper is now part of your project.
![Screenshot 2026-02-28 025552]()
If it is installed you can see in the Dependencies → Packages section under Solution Explorer window in Vs2026
![Screenshot 2026-02-28 025806]()
Another nuget package is needed to install that is Microsoft.Data.SqlClient:
Dapper is not a database driver, in the other hand SQL Server needs a specific ADO.NET provider for that.
For SQL Server, the ADO.NET provider is SqlConnection.
Without this package, your code like:
using var connection = new SqlConnection(connectionString);
will not compile, because SqlConnection won’t exist. Because SqlConnection built-in method comes under this nuget package.
![Screenshot 2026-02-28 030537]()
Step 2: Configure SQL Server Connection String
Open appsettings.json.
{
"ConnectionStrings": {
"AutoWorksDb": "Server=YourServerName;Database=YourDb;Trusted_Connection=True;TrustServerCertificate=True;"
}
}
Explanation
Server=localhost → SQL Server instance
Database=AutoWorksDb → Your database name
Trusted_Connection=True → Windows authentication
TrustServerCertificate=True → Avoid SSL validation issues locally
Step 3: Register IDbConnection in Program.cs
Dapper works with IDbConnection.
We must register it in the dependency injection container.
Program.cs:
using System.Data;
using AutoWorks.Api.Repositories;
using Microsoft.Data.SqlClient;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddScoped<IDbConnection>(sp =>
new SqlConnection(builder.Configuration.GetConnectionString("AutoWorksDb"))); // Give your own Db name
builder.Services.AddScoped<ManufacturerRepository>();
builder.Services.AddScoped<VehicleModelRepository>();
builder.Services.AddScoped<VehicleRepository>();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Why AddScoped?
Each HTTP request gets its own database connection.
Never use AddSingleton for IDbConnection
It causes concurrency issues and broken connections.
Step 4: Creating DTOs for Vehicles
DTOs (Data Transfer Objects) protect your domain and control what enters/leaves your API.
![Screenshot 2026-02-28 031209]()
Using record keeps the code clean and immutable.
Step 5: Building VehicleRepository with Dapper
This is where Dapper shines.
VehicleRepository.cs
using Dapper;
using System.Data;
using AutoWorks.Api.DTOs;
namespace AutoWorks.Api.Repositories;
public class VehicleRepository
{
private readonly IDbConnection _db;
public VehicleRepository(IDbConnection db)
{
_db = db;
}
public async Task<IEnumerable<VehicleReadDto>> GetAllAsync()
{
var sql = """
SELECT VehicleId, VehicleModelId, VIN, Year, Price, CreatedAt
FROM Vehicles
ORDER BY VehicleId DESC;
""";
return await _db.QueryAsync<VehicleReadDto>(sql);
}
public async Task<VehicleReadDto?> GetByIdAsync(int id)
{
var sql = """
SELECT VehicleId, VehicleModelId, VIN, Year, Price, CreatedAt
FROM Vehicles
WHERE VehicleId = @id;
""";
return await _db.QueryFirstOrDefaultAsync<VehicleReadDto>(sql, new { id });
}
public async Task<int> CreateAsync(VehicleCreateDto dto)
{
var sql = """
INSERT INTO Vehicles(VehicleModelId, VIN, Year, Price)
OUTPUT INSERTED.VehicleId
VALUES(@VehicleModelId, @VIN, @Year, @Price);
""";
return await _db.ExecuteScalarAsync<int>(sql, dto);
}
public async Task<bool> UpdateAsync(int id, VehicleUpdateDto dto)
{
var sql = """
UPDATE Vehicles
SET VehicleModelId = COALESCE(@VehicleModelId, VehicleModelId),
VIN = COALESCE(@VIN, VIN),
Year = COALESCE(@Year, Year),
Price = COALESCE(@Price, Price)
WHERE VehicleId = @id;
""";
var rows = await _db.ExecuteAsync(sql, new
{
id,
dto.VehicleModelId,
dto.VIN,
dto.Year,
dto.Price
});
return rows > 0;
}
public async Task<bool> DeleteAsync(int id)
{
var sql = "DELETE FROM Vehicles WHERE VehicleId = @id;";
var rows = await _db.ExecuteAsync(sql, new { id });
return rows > 0;
}
}
Notice how:
Step 6: Creating VehiclesController
VehiclesController.cs
using Microsoft.AspNetCore.Mvc;
using AutoWorks.Api.Repositories;
using AutoWorks.Api.DTOs;
namespace AutoWorks.Api.Controllers;
[ApiController]
[Route("api/[controller]")]
public class VehiclesController : ControllerBase
{
private readonly VehicleRepository _repo;
public VehiclesController(VehicleRepository repo)
{
_repo = repo;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<VehicleReadDto>>> GetAll()
=> Ok(await _repo.GetAllAsync());
[HttpGet("{id:int}")]
public async Task<ActionResult<VehicleReadDto>> GetById(int id)
{
var vehicle = await _repo.GetByIdAsync(id);
return vehicle is null ? NotFound() : Ok(vehicle);
}
[HttpPost]
public async Task<ActionResult> Create([FromBody] VehicleCreateDto dto)
{
var newId = await _repo.CreateAsync(dto);
return CreatedAtAction(nameof(GetById), new { id = newId }, new { VehicleId = newId });
}
[HttpPut("{id:int}")]
public async Task<ActionResult> Update(int id, [FromBody] VehicleUpdateDto dto)
=> await _repo.UpdateAsync(id, dto) ? NoContent() : NotFound();
[HttpDelete("{id:int}")]
public async Task<ActionResult> Delete(int id)
=> await _repo.DeleteAsync(id) ? NoContent() : NotFound();
}
You now have a clean, scalable REST API powered by Dapper.
Step 7: Example Postman Requests
![Screenshot 2026-02-28 022146]()
SQL Server Database:
![Screenshot 2026-02-28 032359]()
Keep SQL in Repository Layer
Controllers should remain thin.
Repositories handle data access logic.
Final Thoughts
You now understand the foundation of Dapper with ASP.NET Core Web API (.NET Core 10):
This is the starting point for building:
Master this foundation, and you gain precise control over performance, SQL execution, and architectural clarity.
In the world of modern backend development, Dapper isn’t just a tool — it’s a strategic choice.
Feel free to comment and ask if is there any questions.