Popcorn > Quick Start > DotNet
Drop Popcorn v8 into a minimal-API app in five minutes. For a full walkthrough (models, test data, multiple endpoints) see Getting Started.
v7 vs v8. This is the v8 (source-generator) path — it works under
PublishAot=TrueandPublishTrimmed=True. If you're on the v7Skyward.Api.Popcorn/.DotNetCorepackages and aren't ready to migrate, the v7 quick start is in the migration guide.
<PackageReference Include="Skyward.Api.Popcorn.SourceGen.Shared" Version="8.0.0-preview.1" />
<PackageReference Include="Skyward.Api.Popcorn.SourceGen" Version="8.0.0-preview.1" PrivateAssets="all" />SourceGen is marked developmentDependency — it only contributes the Roslyn analyzer, never a
runtime DLL. SourceGen.Shared is the runtime library that carries attributes, envelopes, and
middleware.
Popcorn's generator discovers types through standard System.Text.Json
[JsonSerializable] attributes. Register each top-level response type — the generator walks
nested types automatically.
using System.Text.Json.Serialization;
using Popcorn.Shared;
[JsonSerializable(typeof(ApiResponse<List<Car>>))]
[JsonSerializable(typeof(ApiResponse<Car>))]
internal partial class AppJsonSerializerContext : JsonSerializerContext { }using System.Text.Json;
using Popcorn.Shared;
var builder = WebApplication.CreateSlimBuilder(args);
builder.Services.AddHttpContextAccessor();
builder.Services.AddPopcorn();
builder.Services.ConfigureHttpJsonOptions(o =>
{
o.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default);
o.SerializerOptions.AddPopcornOptions(); // installs generator-emitted converters
});
var app = builder.Build();
app.UsePopcornExceptionHandler(); // unhandled exceptions → ApiError envelope
app.MapGet("/cars", (IPopcornAccessor access) =>
access.CreateResponse(new List<Car>
{
new(1, "Pontiac", "Firebird", 1981),
new(2, "Porsche", "Cayman", 2005),
}));
app.Run();
public record Car(int Id, string Make, string Model, int Year);CreateSlimBuilder is the AOT-friendly host builder; if you don't plan to publish as AOT you
can use WebApplication.CreateBuilder(args) instead.
GET /cars
→ { "Success": true, "Data": [{ "Id":1, "Make":"Pontiac", "Model":"Firebird", "Year":1981 }, ...] }
GET /cars?include=[Make,Model]
→ { "Success": true, "Data": [{ "Make":"Pontiac", "Model":"Firebird" }, ...] }
- Getting Started for a fuller walkthrough with multiple models, default-include attributes, and nested sub-entity queries.
- Include Parameter Syntax for the full
?include=grammar (negation, wildcards, nesting). - Default Includes for
[Default]/[Always]/[SubPropertyDefault]attribute usage. - Performance for benchmarked ratios vs raw
System.Text.Jsonand v7. dotnet/PopcornAotExample/for a reference project that publishes withPublishAot=True+PublishTrimmed=True.