skills/backend/aspnet-core/dotnet-10/SKILL.md
Version-specific expert for ASP.NET Core on .NET 10 LTS (Nov 2025 - Nov 2028). Covers OpenAPI 3.1, built-in Minimal API validation, Server-Sent Events TypedResults, Blazor improvements (76% smaller JS, PersistentState, passkeys), Aspire 13, C# 14 features, performance (JIT, stack allocation), and .NET 8 LTS migration guide. WHEN: ".NET 10", "net10.0", "dotnet 10", "OpenAPI 3.1", "AddValidation", "ServerSentEvents", "Aspire 13", "PersistentState", "passkey", "migrate .NET 8 to .NET 10", "C# 14".
npx skillsauth add chrishuffman5/domain-expert backend-aspnet-core-dotnet-10Install this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You are a specialist in ASP.NET Core on .NET 10, the Long-Term Support release (Nov 2025 - Nov 2028). Licensed under MIT.
For foundational ASP.NET Core knowledge (middleware pipeline, DI, Kestrel, routing, controllers vs Minimal APIs), refer to the parent technology agent. This agent focuses on what is new or changed in .NET 10.
The built-in Microsoft.AspNetCore.OpenApi now generates OpenAPI 3.1 documents by default with full JSON Schema draft 2020-12 support:
builder.Services.AddOpenApi(); // Generates OAS 3.1 by default
Nullable type representation changed:
// .NET 9 / OpenAPI 3.0
{ "type": "string", "nullable": true }
// .NET 10 / OpenAPI 3.1
{ "type": ["string", "null"] }
YAML output support:
app.MapOpenApi("/openapi/{documentName}.yaml");
XML doc comments in OpenAPI:
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
/// <summary>Sends a greeting.</summary>
/// <param name="name">The name of the person to greet.</param>
public static string Hello(string name) => $"Hello, {name}!";
app.MapGet("/hello", Program.Hello);
New: GetOrCreateSchemaAsync in transformers:
builder.Services.AddOpenApi(options =>
{
options.AddOperationTransformer(async (operation, context, ct) =>
{
var errorSchema = await context.GetOrCreateSchemaAsync(
typeof(ProblemDetails), null, ct);
context.Document?.AddComponent("Error", errorSchema);
});
});
Response descriptions on ProducesResponseType:
[ProducesResponseType<IEnumerable<WeatherForecast>>(StatusCodes.Status200OK,
Description = "The weather forecast for the next 5 days.")]
Breaking changes:
WithOpenApi() extension deprecated -- remove callsOpenApiAny replaced with JsonNode, Nullable property removedIncludeOpenAPIAnalyzers and Microsoft.Extensions.ApiDescription.Client deprecated// Schema transformer migration
- schema.Example = new OpenApiObject { ["key"] = new OpenApiString("value") };
+ schema.Example = new JsonObject { ["key"] = "value" };
First-class validation with one registration call:
builder.Services.AddValidation();
Once enabled, DataAnnotations validation runs automatically on all Minimal API parameters. Returns standardized 400 Bad Request with ProblemDetails on failure.
public record Product(
[Required] string Name,
[Range(1, 1000)] int Quantity);
app.MapPost("/products", (Product product) => TypedResults.Ok(product));
// Returns 400 ValidationProblem automatically if invalid
Disable per-endpoint:
app.MapPost("/raw", (RawData data) => TypedResults.Ok(data))
.DisableValidation();
Source-generator-based (not reflection) -- AOT-compatible. Validation APIs in Microsoft.Extensions.Validation namespace.
Blazor integration: AddValidation() also enables nested object and collection validation in Blazor forms with [ValidatableType]:
[ValidatableType]
public class Order
{
public Customer Customer { get; set; } = new();
public List<OrderItem> OrderItems { get; set; } = [];
}
app.MapGet("/heartrate", (CancellationToken ct) =>
{
async IAsyncEnumerable<HeartRateRecord> GetHeartRate(
[EnumeratorCancellation] CancellationToken token)
{
while (!token.IsCancellationRequested)
{
yield return HeartRateRecord.Create(Random.Shared.Next(60, 100));
await Task.Delay(2000, token);
}
}
return TypedResults.ServerSentEvents(GetHeartRate(ct), eventType: "heartRate");
});
Passkey authentication (WebAuthn/FIDO2): ASP.NET Core Identity supports passwordless passkeys. Blazor Web App template includes passkey UI out of the box.
Cookie auth no longer redirects for API endpoints (breaking): For endpoints identified as API endpoints ([ApiController], Minimal APIs returning JSON, TypedResults, SignalR), cookie auth returns 401/403 directly instead of redirecting.
// Override to restore redirect behavior
builder.Services.AddAuthentication()
.AddCookie(options =>
{
options.Events.OnRedirectToLogin = context =>
{
context.Response.Redirect(context.RedirectUri);
return Task.CompletedTask;
};
});
New auth metrics: Microsoft.AspNetCore.Authentication, Microsoft.AspNetCore.Authorization, Microsoft.AspNetCore.Identity meters for Aspire/OpenTelemetry dashboards.
.localhost TLD support: Dev cert valid for *.dev.localhost:
dotnet new web -n MyApp --localhost-tld
JIT: Struct code generation, improved loop inversion, array interface devirtualization, methods with try-finally can be inlined.
Stack allocation: Small fixed-size arrays of value types and reference types, objects referenced by local struct fields, and some Func<> closures can now be stack-allocated.
// Stack-allocated in .NET 10
string[] words = {"Hello", "World!"};
foreach (var str in words) Console.WriteLine(str);
Kestrel: Automatic memory pool eviction when idle. New Microsoft.AspNetCore.MemoryPool meter.
JSON + PipeReader: MVC and Minimal API deserialization now uses PipeReader-based parsing for improved throughput with large payloads.
HTTP/3 disabled with PublishTrimmed: Opt-in required:
<PropertyGroup>
<PublishTrimmed>true</PublishTrimmed>
<EnableHttp3>true</EnableHttp3>
</PropertyGroup>
76% smaller JS bundle: blazor.web.js dropped from ~183 KB to ~43 KB.
[PersistentState] attribute: Replaces verbose PersistentComponentState pattern:
@code {
[PersistentState]
public List<Movie>? MoviesList { get; set; }
protected override async Task OnInitializedAsync()
{
MoviesList ??= await MovieService.GetMoviesAsync();
}
}
Advanced options: AllowUpdates, RestoreBehavior.SkipInitialValue, RestoreBehavior.SkipLastSnapshot.
Improved form validation: Source-generator-based (AOT-safe), nested objects and collections. Use [SkipValidation] to exclude properties.
New JS interop APIs: InvokeConstructorAsync, GetValueAsync, SetValueAsync.
ReconnectModal component in template with CSP-compliant reconnection UI.
Not-Found handling: NavigationManager.NotFound() and NotFoundPage on Router.
HttpClient response streaming enabled by default (breaking): Opt out with SetBrowserResponseStreamingEnabled(false).
Aspire 13 ships alongside .NET 10. The ".NET" prefix is dropped -- now just Aspire.
Polyglot platform:
var api = builder.AddPythonApp("fastapi-backend", "backend/", "main.py")
.WithUvicorn();
var frontend = builder.AddJavaScriptApp("react-frontend", "frontend/")
.WithVite()
.WaitFor(api);
Single-file AppHost:
#:sdk [email protected]
var builder = DistributedApplication.CreateBuilder(args);
var db = builder.AddPostgres("db").AddDatabase("appdb");
var api = builder.AddProject<Projects.MyApi>("api").WithReference(db);
await builder.Build().RunAsync();
aspire do pipeline: aspire do build, aspire do deploy --target azure.
Dashboard MCP Server: AI assistants can query resources and telemetry.
| Feature | Description |
|---|---|
| field keyword | Field-backed properties in get/set |
| Extension blocks | extension keyword for static/instance extensions |
| Null-conditional assignment | x?.Property = value |
| nameof unbound generics | nameof(List<>) |
| Span implicit conversions | First-class Span<T> / ReadOnlySpan<T> |
| Partial constructors | partial instance constructors and events |
| Lambda ref params | ref, in, out in lambdas without explicit types |
The recommended enterprise path is .NET 8 -> .NET 10 (skipping .NET 9). Plan 3-6 months for large projects.
1. Update TFM:
- <TargetFramework>net8.0</TargetFramework>
+ <TargetFramework>net10.0</TargetFramework>
2. Update global.json:
- "version": "8.0.xxx"
+ "version": "10.0.100"
3. Update NuGet packages to 10.0.x for all Microsoft.AspNetCore.*, Microsoft.EntityFrameworkCore.*, Microsoft.Extensions.*.
4. Run Upgrade Assistant:
dotnet tool install -g upgrade-assistant
upgrade-assistant upgrade ./MyApp.sln
5. Address WebHostBuilder obsolescence:
- var host = new WebHostBuilder().UseKestrel().UseStartup<Startup>().Build();
+ var builder = WebApplication.CreateBuilder(args);
+ var app = builder.Build();
+ app.Run();
6. Address OpenAPI changes:
- app.MapGet("/hello", () => "Hello").WithOpenApi();
+ app.MapGet("/hello", () => "Hello");
- <IncludeOpenAPIAnalyzers>true</IncludeOpenAPIAnalyzers>
+ <OpenApiGenerateDocuments>true</OpenApiGenerateDocuments>
7. Address auth changes: Cookie auth returns 401/403 for API endpoints. Add explicit redirect handlers if old behavior was intentional.
8. Replace KnownNetworks:
- options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("10.0.0.0"), 8));
+ options.KnownIpNetworks.Add(new IPNetwork(IPAddress.Parse("10.0.0.0"), 8));
9. Enable new features (optional):
builder.Services.AddValidation(); // Auto-validation for Minimal APIs
10. Test: Container images now Ubuntu (not Debian). W3C trace context is default propagator. Verify auth flows and Blazor reconnection UI.
| Change | Type | Action |
|---|---|---|
| WithOpenApi() deprecated | Source | Remove calls |
| OpenAPI 3.1 default + OpenAPI.NET 2.0 | Source | Update transformers to JsonNode |
| WebHostBuilder / IWebHost obsolete | Source | Migrate to WebApplication |
| IPNetwork / KnownNetworks obsolete | Source | Use KnownIpNetworks |
| Cookie auth no longer redirects for APIs | Behavioral | Verify auth flows |
| Exception diagnostics suppressed when handled | Behavioral | Add explicit logging |
| Default container images Ubuntu | Behavioral | Check OS-specific code |
| HTTP/3 disabled with PublishTrimmed | Build | Add <EnableHttp3>true</EnableHttp3> |
| blazor.boot.json inlined into dotnet.js | Build | Update integrity scripts |
| Blazor HttpClient streaming enabled by default | Behavioral | Opt out if needed |
net10.0tools
kubectl command-line usage and scripting: kubeconfig and context management, output formats (jsonpath, custom-columns, go-template), all major verbs (get, describe, apply, delete, exec, logs, port-forward, rollout, scale, drain), workload resources, config/storage, networking, RBAC, node management, debugging (CrashLoopBackOff, ImagePullBackOff, OOMKilled), and scripting patterns (dry-run, diff, wait, jq, kustomize). WHEN: "kubectl", "k8s CLI", "kubeconfig", "namespace", "pod", "deployment", "service", "ingress", "configmap", "secret", "rollout", "scale", "drain", "taint", "kustomize". Do NOT use for cluster architecture, sizing, upgrades, or workload design decisions — that's the `kubernetes` skill in the `containers` plugin. This skill is command syntax and scripting kubectl against an existing cluster, not cluster ops.
tools
Bash 5.x shell scripting, Unix text processing, and command-line automation: variables, parameter expansion, quoting, control flow, functions, I/O redirection, error handling (set -euo pipefail, trap), and the Unix tool ecosystem (grep, sed, awk, jq, find, sort, uniq, cut, xargs). Covers process management, networking (curl, ssh, rsync, nc), file locking (flock), parallel execution, and production script patterns. WHEN: "Bash", "bash", "shell", "sh", ".sh", "shell script", "sed", "awk", "grep", "jq", "find", "xargs", "curl", "ssh", "rsync", "cron", "pipe", "redirect", "here-doc", "shebang", "POSIX", "set -euo pipefail", "trap".
tools
Azure CLI (az) command syntax and scripting: authentication (interactive, service principal, managed identity, SSO), output formats and JMESPath queries, resource groups, VMs, storage accounts/blobs, networking (VNets, NSGs, load balancers, DNS), Entra ID, AKS, App Service, Functions, databases (SQL, Cosmos DB, MySQL, PostgreSQL), Key Vault, Monitor/alerting, and infrastructure scripting patterns. WHEN: "az ", "Azure CLI", "az login", "az vm", "az aks", "az storage", "az keyvault", "az monitor", "az ad", "az group", "az network", "az webapp", "az functionapp", "az sql", "az cosmosdb", "JMESPath", "az account". Do NOT use for Azure architecture, landing zones, or multi-subscription strategy — that's the `cloud-platforms` plugin. This skill is about command syntax and scripting the CLI, not deciding what to provision.
tools
AWS CLI v2 command syntax and scripting: authentication (profiles, SSO, assume-role, instance profiles), output formats and JMESPath queries, pagination and waiters, IAM, S3, Lambda, RDS, CloudFormation, ECS, EKS, CloudWatch, SSM, Route 53, STS, and VPC networking. WHEN: "aws ", "AWS CLI", "aws ec2", "aws s3", "aws lambda", "aws iam", "aws cloudformation", "aws ssm", "aws ecs", "aws eks", "aws rds", "aws cloudwatch", "aws route53", "aws sts". Do NOT use for AWS architecture, service selection, multi-account strategy, or FinOps — that's the `cloud-platforms` plugin. This skill is about command syntax and scripting the CLI, not deciding what to provision.