DEV Community

IronSoftware
IronSoftware

Posted on

How to Develop ASP.NET Applications in .NET 10

.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();
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

Now (.NET 10):

using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder();
builder.Services.AddControllers();

var app = builder.Build();
app.MapControllers();
app.Run();
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Run the app:

dotnet run
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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"}
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Project structure:

MyMvcApp/
├── Controllers/
│   └── HomeController.cs
├── Views/
│   ├── Home/
│   │   └── Index.cshtml
│   └── Shared/
│       └── _Layout.cshtml
├── wwwroot/
│   ├── css/
│   └── js/
└── Program.cs
Enter fullscreen mode Exit fullscreen mode

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");
    }
}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

Option 3: Blazor (Interactive Web UIs)

Best for: SPAs without JavaScript, interactive dashboards

Create Blazor Server app:

dotnet new blazor -n MyBlazorApp
cd MyBlazorApp
Enter fullscreen mode Exit fullscreen mode

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++;
    }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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; }
}
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

Connection string (appsettings.json):

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=localhost;Database=MyApp;Trusted_Connection=True;TrustServerCertificate=True"
  }
}
Enter fullscreen mode Exit fullscreen mode

Create migration:

dotnet ef migrations add InitialCreate
dotnet ef database update
Enter fullscreen mode Exit fullscreen mode

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");
    }
}
Enter fullscreen mode Exit fullscreen mode

Authentication and Authorization

Add Identity (User Authentication)

Install package:

dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
Enter fullscreen mode Exit fullscreen mode

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; }
}
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

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();
    }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"]
Enter fullscreen mode Exit fullscreen mode

Build and run:

docker build -t myapp .
docker run -p 8080:80 myapp
Enter fullscreen mode Exit fullscreen mode

Access app: http://localhost:8080

Option 3: Deploy to AWS Elastic Beanstalk

Install AWS CLI and EB CLI:

pip install awsebcli
Enter fullscreen mode Exit fullscreen mode

Initialize:

eb init -p "64bit Amazon Linux 2023 v3.0.0 running .NET 10" myapp
Enter fullscreen mode Exit fullscreen mode

Create environment:

eb create myapp-env
Enter fullscreen mode Exit fullscreen mode

Deploy:

dotnet publish -c Release
eb deploy
Enter fullscreen mode Exit fullscreen mode

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;
});
Enter fullscreen mode Exit fullscreen mode

Good (asynchronous):

app.MapGet("/api/products", async () =>
{
    var products = await _db.Products.ToListAsync(); // Non-blocking
    return products;
});
Enter fullscreen mode Exit fullscreen mode

Enable Response Compression

Add compression:

builder.Services.AddResponseCompression(options =>
{
    options.EnableForHttps = true;
});

var app = builder.Build();
app.UseResponseCompression();
Enter fullscreen mode Exit fullscreen mode

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();
    });
});
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)