.NET Web API Core
Hey everyone! In this article, I'll walk you through every element of .NET Web API Core, covering everything from the Program.cs file to SwaggerUI integration.
Introduction
.NET Web API Core is a framework for building RESTful services using .NET Core. It allows applications to communicate over HTTP using standard web protocols. It is lightweight, cross-platform, and supports dependency injection, middleware, and routing.
Key Features:
Understanding Program.cs in .NET Core
In .NET Core, the Program.cs file is the entry point of the application. It is responsible for configuring and starting the application. The structure of Program.cs has evolved, and in .NET 6 and later, it follows a minimal hosting model.
A typical Program.cs file in a .NET 6+ Web API project looks like this:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
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();
Breaking Down the Elements in Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
Configuring Middleware
Middleware in .NET Core controls the request processing pipeline.
a. if (app.Environment.IsDevelopment()) { ... }
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
b. app.UseHttpsRedirection();
Forces HTTPS redirection, ensuring secure communication.
app.UseHttpsRedirection();
c. app.UseAuthorization();
app.MapControllers();
app.Run();
Starts the application and begins listening for incoming HTTP requests.
Dependency Injection
Dependency Injection (DI) is a design pattern used in .NET Core to achieve loose coupling between components. Instead of creating instances of dependencies manually, they are injected by the framework.
Benefits of Dependency Injection:
Dependency Injection (DI) Scopes
In .NET Core, Dependency Injection (DI) supports three lifetime scopes to control the lifetime of service instances:
1. Transient (Short-lived)
Registration:
builder.Services.AddTransient<IProductService, ProductService>();
Example:
public class ProductService : IProductService
{
public Guid Id { get; } = Guid.NewGuid();
}
If you inject ProductService multiple times in a single request, each injection gets a new instance.
2. Scoped (Request-lifetime)
Registration:
builder.Services.AddScoped<IProductService, ProductService>();
Example: If ProductService is injected into multiple components within the same request, they all share the same instance.
3. Singleton (Application-wide)
Registration:
builder.Services.AddSingleton<IProductService, ProductService>();
Example: All requests share the same instance throughout the application lifecycle.
Testing DI Scopes
Modify ProductService to track instance lifetime using a Guid:
public class ProductService : IProductService
{
public Guid Id { get; } = Guid.NewGuid();
public string GetServiceId() => Id.ToString();
}
Inject into a controller:
[ApiController]
[Route("api/products")]
public class ProductController : ControllerBase
{
private readonly IProductService _productService;
public ProductController(IProductService productService)
{
_productService = productService;
}
[HttpGet("service-id")]
public IActionResult GetServiceId()
{
return Ok(_productService.GetServiceId());
}
}
Test via API Calls
Choosing the Right DI Scope
Routing & Middleware
Routing in .NET Core defines how HTTP requests are mapped to controller actions. It helps navigate different API endpoints based on the URL pattern.
Types of Routing in .NET Core
1. Attribute Routing
Uses attributes on controllers and actions to define routes.
Example:
[ApiController]
[Route("api/products")]
public class ProductController : ControllerBase
{
[HttpGet] // Matches "GET api/products"
public IActionResult GetAll()
{
return Ok(new List<string> { "Laptop", "Phone" });
}
[HttpGet("{id}")] // Matches "GET api/products/{id}"
public IActionResult GetById(int id)
{
return Ok($"Product {id}");
}
[HttpPost] // Matches "POST api/products"
public IActionResult AddProduct(string name)
{
return Created("api/products", name);
}
}
Advanced Attribute Routing
[HttpGet("category/{category}/page/{page}")]
public IActionResult GetByCategory(string category, int page)
{
return Ok($"Category: {category}, Page: {page}");
}
Matches: GET api/products/category/laptops/page/2
2. Convention-based Routing
Defines routes globally inside Program.cs.
Example:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Matches: /Home/Index or /Home/Index/5
2. Middleware in .NET Core
Middleware is a pipeline of components that handle HTTP requests and responses.
How Middleware Works
Each middleware processes requests before passing them to the next component.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseMiddleware<CustomMiddleware>(); // Custom middleware
app.UseHttpsRedirection(); // Redirects HTTP to HTTPS
app.UseAuthorization(); // Handles authentication
app.MapControllers(); // Maps API controllers
app.Run();
Common Built-in Middleware in .NET Core
Custom Middleware Example
To create a custom middleware, implement the InvokeAsync() method.
1. Create a Custom Middleware Class
public class CustomMiddleware
{
private readonly RequestDelegate _next;
public CustomMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
Console.WriteLine($"Request URL: {context.Request.Path}");
await _next(context); // Call the next middleware
}
}
2. Register Middleware in Program.cs
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseMiddleware<CustomMiddleware>(); // Register custom middleware
app.MapControllers();
app.Run();
Logs each request URL in the console before passing control to the next middleware.
API Versioning & Authentication
1. API Versioning
API versioning allows maintaining multiple versions of an API to ensure backward compatibility.
Why Use API Versioning?
Step 1: Install API Versioning Package
Run the following command:
dotnet add package Microsoft.AspNetCore.Mvc.Versioning
Step 2: Configure API Versioning in Program.cs
Add API versioning support in the DI container:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddApiVersioning(options =>
{
options.ReportApiVersions = true; // Adds API version headers in responses
options.AssumeDefaultVersionWhenUnspecified = true;
options.DefaultApiVersion = new ApiVersion(1, 0); // Default API version
});
Step 3: Implement API Versioning in Controllers
There are three ways to specify API versions:
1. URL-based Versioning
[ApiController]
[Route("api/v{version:apiVersion}/products")]
[ApiVersion("1.0")]
public class ProductsV1Controller : ControllerBase
{
[HttpGet]
public IActionResult Get() => Ok(new string[] { "Laptop", "Phone" });
}
Access via: GET /api/v1/products
2. Query String Versioning
[ApiController]
[Route("api/products")]
[ApiVersion("2.0")]
public class ProductsV2Controller : ControllerBase
{
[HttpGet]
public IActionResult Get() => Ok(new string[] { "Tablet", "Smartwatch" });
}
Access via: GET /api/products?api-version=2.0
3. Header-based Versioning
Add versioning using HTTP headers.
options.ApiVersionReader = new HeaderApiVersionReader("X-API-Version");
Access via:
GET /api/products
Headers: X-API-Version: 2.0
Step 4: Test API Versioning
Now, you can call different API versions using URLs, query strings, or headers.
2. Authentication
Authentication ensures that only authorized users can access protected resources.
Common Authentication Methods:
Implementing JWT Authentication in .NET Core
Step 1: Install Required Packages
Run:
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
Step 2: Configure JWT Authentication in Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "https://yourdomain.com",
ValidAudience = "https://yourdomain.com",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("YourSecretKeyHere"))
};
});
builder.Services.AddAuthorization();
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
Step 3: Protect API Endpoints with [Authorize]
[ApiController]
[Route("api/secure")]
public class SecureController : ControllerBase
{
[HttpGet]
[Authorize] // Only authenticated users can access this
public IActionResult GetSecureData()
{
return Ok("This is a protected API endpoint!");
}
}
Step 4: Generate a JWT Token for Users
Create an endpoint to generate JWT tokens.
[ApiController]
[Route("api/auth")]
public class AuthController : ControllerBase
{
[HttpPost("login")]
public IActionResult Login(string username, string password)
{
if (username == "admin" && password == "password")
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes("YourSecretKeyHere");
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, username) }),
Expires = DateTime.UtcNow.AddHours(1),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
return Ok(new { token = tokenHandler.WriteToken(token) });
}
return Unauthorized();
}
}
Step 5: Test Authentication
POST /api/auth/login
Content-Type: application/json
{
"username": "admin",
"password": "password"
}
Response:
{ "token": "eyJhbGciOi..." }
2. Access a protected API with the token:
GET /api/secure
Authorization: Bearer eyJhbGciOi...
Swagger UI Integration
Swagger (OpenAPI) is a specification for documenting APIs.
It provides:
Step 1: Install Swagger Package
Run the following command in your terminal or package manager console:
dotnet add package Swashbuckle.AspNetCore
Step 2: Configure Swagger in Program.cs
Modify Program.cs to register Swagger services:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
// Add Swagger services
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Enable Swagger in development mode
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Step 3: Run the Application
Start your application and navigate to:
https://localhost:<port>/swagger
You will see an interactive Swagger UI listing all API endpoints.
Step 4: Customize Swagger UI
Modify Swagger configuration to include metadata like API title, description, and version:
builder.Services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo
{
Title = "My API",
Version = "v1",
Description = "A simple ASP.NET Core Web API with Swagger",
Contact = new OpenApiContact
{
Name = "Your Name",
Email = "your@email.com",
Url = new Uri("https://yourwebsite.com")
}
});
});
Now, Swagger UI will display detailed API information.
Step 5: Enable Authorization in Swagger UI
If your API uses JWT authentication, modify SwaggerGen to include a security definition:
using Microsoft.OpenApi.Models;
builder.Services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo
{
Title = "My API",
Version = "v1"
});
// Add JWT Authentication
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Name = "Authorization",
Type = SecuritySchemeType.Http,
Scheme = "Bearer",
BearerFormat = "JWT",
In = ParameterLocation.Header,
Description = "Enter 'Bearer {token}'"
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
Array.Empty<string>()
}
});
});
Now, Swagger UI will have an "Authorize" button to enter a JWT token for protected APIs.
Step 6: Test Swagger UI
Conclusion:
This article covered the essential elements of building a .NET Core Web API, including routing, middleware, dependency injection, authentication, API versioning, and Swagger integration. Each component plays a crucial role in creating scalable, secure, and maintainable APIs.
By following these principles, developers can:
With these foundations, you can confidently develop robust RESTful APIs in .NET Core.
Asp.Net Core 8 | Angular | .Net Web API | PHP | Laravel C,C+,C# | Backend Architect | Team Lead | Delivering Tailored Business Solutions Across Multiple Industries
4movery detailed and easily understable. Thank You for sharing
Sharing Ad-Hoc startup Anecdotes. 💥
4moGreat insights on .NET Web API Core! Looking forward to learning more.
Technical Lead
4moClear and easily understandable... Thank you for sharing...
Sr .Net Consultant
4moDetailed and well written.
Quick information thank you for sharing Ramu Kunja