.NET 10 is here, and ASP.NET Core has never been better for building web applications. Whether you're building APIs, web apps, or real-time services, .NET 10 delivers improved performance, simplified hosting, and better developer experience.
Here's how to develop ASP.NET applications in .NET 10 from setup to deployment.
What is ASP.NET Core?
ASP.NET Core is Microsoft's cross-platform framework for building modern web applications and APIs.
What you can build:
- Web applications (MVC, Razor Pages, Blazor)
- REST APIs (Web API, Minimal APIs)
- Real-time services (SignalR)
- Microservices (gRPC, REST)
// Minimal API in .NET 10 (one file)
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello from .NET 10!");
app.MapGet("/api/products", () => new[] { "Product 1", "Product 2" });
app.Run();
Result: Web API running on http://localhost:5000 with two endpoints.
What's New in ASP.NET Core for .NET 10?
Performance Improvements
.NET 10 is faster than .NET 8:
- 15-20% faster request handling
- Reduced memory allocations
- Improved JSON serialization
- Better HTTP/3 support
Simplified Hosting Model
Before (.NET 6-8):
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
var app = builder.Build();
app.UseRouting();
app.UseAuthorization();
app.MapControllers();
app.Run();
Now (.NET 10):
using Microsoft.AspNetCore.Mvc;
var builder = WebApplication.CreateBuilder();
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
Less boilerplate, same functionality.
Native AOT Support
.NET 10 supports Native Ahead-of-Time (AOT) compilation:
- 90% faster startup
- 50% smaller memory footprint
- Perfect for serverless (AWS Lambda, Azure Functions)
Enable AOT in .csproj:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<PublishAot>true</PublishAot>
</PropertyGroup>
</Project>
Result: 50MB API becomes 15MB executable with instant startup.
Improved Blazor
Blazor in .NET 10:
- Streaming rendering (faster initial page load)
- Enhanced form handling
- Better JavaScript interop
- Improved error handling
How to Get Started with ASP.NET Core in .NET 10
Step 1: Install .NET 10 SDK
Download from: https://dotnet.microsoft.com/download
Verify installation:
dotnet --version
Expected output: 10.0.0 or higher
Step 2: Create Your First Web App
Create a new Minimal API project:
dotnet new web -n MyFirstApp
cd MyFirstApp
Run the app:
dotnet run
Open browser: http://localhost:5000
Result: "Hello World!" displayed in browser.
Step 3: Add Endpoints
Edit Program.cs:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// GET: Returns plain text
app.MapGet("/", () => "Welcome to .NET 10!");
// GET: Returns JSON
app.MapGet("/api/time", () => new { time = DateTime.UtcNow });
// POST: Accepts JSON body
app.MapPost("/api/echo", (EchoRequest request) => new { message = $"You said: {request.Message}" });
app.Run();
record EchoRequest(string Message);
Test the API:
curl http://localhost:5000/api/time
# {"time":"2025-01-26T10:30:00Z"}
curl -X POST http://localhost:5000/api/echo \
-H "Content-Type: application/json" \
-d '{"message":"Hello from curl"}'
# {"message":"You said: Hello from curl"}
Building Different Types of Applications
Option 1: Minimal APIs (REST APIs)
Best for: Lightweight APIs, microservices, serverless
using Microsoft.AspNetCore.Mvc;
var builder = WebApplication.CreateBuilder(args);
// Add services
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Enable Swagger (API documentation)
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
// Define endpoints
app.MapGet("/api/products", () => new[]
{
new Product(1, "Laptop", 999.99m),
new Product(2, "Mouse", 29.99m)
});
app.MapGet("/api/products/{id}", (int id) =>
{
var products = new[]
{
new Product(1, "Laptop", 999.99m),
new Product(2, "Mouse", 29.99m)
};
var product = products.FirstOrDefault(p => p.Id == id);
return product is not null ? Results.Ok(product) : Results.NotFound();
});
app.MapPost("/api/products", (Product product) =>
{
// Save to database here
return Results.Created($"/api/products/{product.Id}", product);
});
app.Run();
record Product(int Id, string Name, decimal Price);
Features:
- ✅ Minimal boilerplate
- ✅ Strongly-typed parameters
- ✅ Automatic JSON serialization
- ✅ Built-in Swagger documentation
Option 2: MVC Web Applications
Best for: Traditional server-rendered web apps
Create MVC app:
dotnet new mvc -n MyMvcApp
cd MyMvcApp
Project structure:
MyMvcApp/
├── Controllers/
│ └── HomeController.cs
├── Views/
│ ├── Home/
│ │ └── Index.cshtml
│ └── Shared/
│ └── _Layout.cshtml
├── wwwroot/
│ ├── css/
│ └── js/
└── Program.cs
Controller example:
using Microsoft.AspNetCore.Mvc;
public class ProductsController : Controller
{
private readonly IProductRepository _repository;
public ProductsController(IProductRepository repository)
{
_repository = repository;
}
// GET: /products
public IActionResult Index()
{
var products = _repository.GetAll();
return View(products);
}
// GET: /products/details/5
public IActionResult Details(int id)
{
var product = _repository.GetById(id);
if (product == null)
return NotFound();
return View(product);
}
// POST: /products/create
[HttpPost]
public IActionResult Create(Product product)
{
if (!ModelState.IsValid)
return View(product);
_repository.Add(product);
return RedirectToAction("Index");
}
}
View example (Razor):
@model List<Product>
<h1>Products</h1>
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Price</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var product in Model)
{
<tr>
<td>@product.Name</td>
<td>@product.Price.ToString("C")</td>
<td><a asp-action="Details" asp-route-id="@product.Id">View</a></td>
</tr>
}
</tbody>
</table>
Option 3: Blazor (Interactive Web UIs)
Best for: SPAs without JavaScript, interactive dashboards
Create Blazor Server app:
dotnet new blazor -n MyBlazorApp
cd MyBlazorApp
Component example (Counter.razor):
@page "/counter"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
Result: Interactive counter with zero JavaScript, all C#.
Working with Databases
Entity Framework Core Setup
Install packages:
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Design
Define DbContext:
using Microsoft.EntityFrameworkCore;
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
public DbSet<Product> Products { get; set; }
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = "";
public decimal Price { get; set; }
}
Configure in Program.cs:
var builder = WebApplication.CreateBuilder(args);
// Add Entity Framework
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
var app = builder.Build();
Connection string (appsettings.json):
{
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=MyApp;Trusted_Connection=True;TrustServerCertificate=True"
}
}
Create migration:
dotnet ef migrations add InitialCreate
dotnet ef database update
Use in controllers:
public class ProductsController : Controller
{
private readonly AppDbContext _db;
public ProductsController(AppDbContext db)
{
_db = db;
}
public async Task<IActionResult> Index()
{
var products = await _db.Products.ToListAsync();
return View(products);
}
[HttpPost]
public async Task<IActionResult> Create(Product product)
{
if (!ModelState.IsValid)
return View(product);
_db.Products.Add(product);
await _db.SaveChangesAsync();
return RedirectToAction("Index");
}
}
Authentication and Authorization
Add Identity (User Authentication)
Install package:
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
Update DbContext:
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
public class AppDbContext : IdentityDbContext<IdentityUser>
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
public DbSet<Product> Products { get; set; }
}
Configure in Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
// Add Identity
builder.Services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<AppDbContext>()
.AddDefaultTokenProviders();
builder.Services.AddControllersWithViews();
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Protect endpoints:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
[Authorize] // Requires login
public class DashboardController : Controller
{
public IActionResult Index()
{
var userName = User.Identity?.Name;
return View();
}
}
[Authorize(Roles = "Admin")] // Requires Admin role
public class AdminController : Controller
{
public IActionResult Index()
{
return View();
}
}
Deploying ASP.NET Core Applications
Option 1: Deploy to Azure App Service
Publish from CLI:
# Login to Azure
az login
# Create resource group
az group create --name MyResourceGroup --location eastus
# Create App Service plan
az appservice plan create --name MyPlan --resource-group MyResourceGroup --sku B1
# Create web app
az webapp create --name MyUniqueAppName --resource-group MyResourceGroup --plan MyPlan
# Deploy
dotnet publish -c Release
cd bin/Release/net10.0/publish
zip -r app.zip *
az webapp deployment source config-zip --resource-group MyResourceGroup --name MyUniqueAppName --src app.zip
Access app: https://MyUniqueAppName.azurewebsites.net
Option 2: Deploy to Docker
Dockerfile:
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
WORKDIR /app
EXPOSE 80
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY ["MyApp.csproj", "./"]
RUN dotnet restore "MyApp.csproj"
COPY . .
RUN dotnet build "MyApp.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "MyApp.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "MyApp.dll"]
Build and run:
docker build -t myapp .
docker run -p 8080:80 myapp
Access app: http://localhost:8080
Option 3: Deploy to AWS Elastic Beanstalk
Install AWS CLI and EB CLI:
pip install awsebcli
Initialize:
eb init -p "64bit Amazon Linux 2023 v3.0.0 running .NET 10" myapp
Create environment:
eb create myapp-env
Deploy:
dotnet publish -c Release
eb deploy
Performance Best Practices
Use Async/Await for I/O Operations
Bad (synchronous):
app.MapGet("/api/products", () =>
{
var products = _db.Products.ToList(); // Blocks thread
return products;
});
Good (asynchronous):
app.MapGet("/api/products", async () =>
{
var products = await _db.Products.ToListAsync(); // Non-blocking
return products;
});
Enable Response Compression
Add compression:
builder.Services.AddResponseCompression(options =>
{
options.EnableForHttps = true;
});
var app = builder.Build();
app.UseResponseCompression();
Result: 60-70% smaller response sizes.
Use Caching
In-memory caching:
builder.Services.AddMemoryCache();
var app = builder.Build();
app.MapGet("/api/products", async (IMemoryCache cache, AppDbContext db) =>
{
return await cache.GetOrCreateAsync("products", async entry =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5);
return await db.Products.ToListAsync();
});
});
Result: Database queries cached for 5 minutes.
The Bottom Line: ASP.NET Core in .NET 10
ASP.NET Core .NET 10 delivers:
- ✅ 15-20% better performance over .NET 8
- ✅ Simplified hosting model (less boilerplate)
- ✅ Native AOT support (50% smaller, 90% faster startup)
- ✅ Improved Blazor (streaming rendering, better forms)
- ✅ Cross-platform (Windows, Linux, macOS, Docker)
Getting started is simple:
dotnet new web -n MyApp
cd MyApp
dotnet run
You're building modern web apps in minutes.
Written by Jacob Mellor, CTO at Iron Software. Jacob created IronPDF and leads a team of 50+ engineers building .NET document processing libraries.
Top comments (0)