Comparison

Master vs ASP.NET Core

ASP.NET Core is Microsoft’s mature, high-performance web framework with Entity Framework and a polished tooling story. Master deliberately mirrors its enterprise toolkit — MasterController 2.3–2.11 added scoped DI, model binding and ProblemDetails, auth policies, layered configuration and user secrets, hosted services, structured logging, caching and compression, OpenAPI, minimal APIs, versioning, localization, health checks and an in-process test host — in the JavaScript ecosystem, with a Next.js frontend included.

At a glance

Feature by feature

FeatureMasterASP.NET Core
LanguageJavaScript (ESM) / Node 22.12+C# / .NET
PatternMVC API + minimal APIs + Next.js frontendMVC / Minimal APIs + Razor / Blazor
Composition rootserver.js (setupServer → addScoped → use* → startMVC → start)Program.cs (builder.Services → app.Use* → MapControllers)
Dependency injectionaddSingleton / addScoped, real per-request scope, services on this.*Singleton / Scoped / Transient, constructor injection
ORMMasterRecord (scoped AppContext, this.db)Entity Framework Core (scoped DbContext)
Migrations CLImaster db new / migrate / rollback / status / script / removedotnet ef migrations add / database update / list / script / remove
Scaffoldingmaster g scaffold (validated REST controller + model + page)dotnet aspnet-codegenerator / templates
Model binding & validationstatic schemas → this.model, 400 ValidationProblemDetails[ApiController] + DataAnnotations / FluentValidation
Error contractRFC 7807 ProblemDetailsRFC 7807 ProblemDetails
Typed resultsthis.ok / created / noContent / notFound / problem / fileOk() / Created() / NoContent() / NotFound() / Problem() / File()
Typed route constraints/posts/:id(int)/posts/{id:int}
AuthenticationJWT bearer (HS/RS/PS/ES), signed cookies, custom schemes, password hasherJWT bearer, cookies, Identity, external providers
Authorizationauthorize on routes / controllers / actions, roles, policies, ClaimsPrincipal (this.user)[Authorize], roles, policies, ClaimsPrincipal
Configurationappsettings.json → appsettings.{env}.json → user secrets → env vars → CLI; options pattern validated on startIConfiguration layering; IOptions<T> + ValidateOnStart
User secretsmaster secrets set Auth:JwtSecret …dotnet user-secrets set …
Hosted services / background workaddHostedService, BackgroundService, PeriodicTimerService, queueIHostedService, BackgroundService, PeriodicTimer
Loggingthis.logger / createLogger(category), levels per category, scopes, X-Request-Id, JSON providerILogger<T>, scopes, providers
Caching & compressionoutputCache policies, master.cache (memory/Redis), useResponseCompression (gzip/br)Output caching, IDistributedCache, ResponseCompression
OpenAPI / SwaggeruseOpenApi → /openapi.json + Swagger UI, generated from routes + schemas + authAddOpenApi / Swashbuckle
Minimal APIs / route groups / named routesmaster.map.get(...), router.group(...), urlFor(name)MapGet, MapGroup, WithName + LinkGenerator
API versioninguseApiVersioning (query / header / media-type / url-segment)Asp.Versioning
LocalizationuseRequestLocalization, this.localizer, Content-LanguageRequestLocalization, IStringLocalizer
Health checks/health/live, /health/ready, /health/report (Healthy / Degraded / Unhealthy)AddHealthChecks / MapHealthChecks
Integration testingmaster.createTestClient() (in-process), master testWebApplicationFactory + HttpClient, dotnet test
Graceful shutdownuseGracefulShutdown (SIGTERM → drain → stop hosted services)IHostApplicationLifetime
Real-timeSocket.IO socket controllersSignalR
FrontendNext.js (React) included in the scaffoldRazor Pages / Blazor / SPA templates
Static typingOptional (TypeScript on the frontend; backend is plain ESM JS)C# — compile-time everywhere
gRPC
RuntimeNode (V8).NET CLR (very fast, AOT available)
Deploy targetsAnywhere Node runsAnywhere .NET runs
Show me the code

The same controller, side by side

Master
Master
// backend/app/controllers/postsController.js (generated by master g scaffold)
export default class PostsController {
  static schemas = {                                  // [ApiController] model binding + validation
    create: { body: { title: { type: 'string', required: true } } },
  };
  static authorize = { create: true };                // [Authorize] on one action

  constructor(requestObject) { this.requestObject = requestObject; }

  async index() {                                     // this.db = scoped AppContext (DbContext)
    this.ok({ data: await this.db.Post.toList() });
  }

  async show(obj) {                                   // route: /posts/:id(int)
    const post = await this.db.Post.find(obj.params.id);
    if (!post) return this.notFound('Post not found');
    this.ok({ data: post });
  }

  async create() {                                    // invalid body -> 400 ValidationProblemDetails
    const post = this.db.Post.new();
    Object.assign(post, this.model);
    await this.db.saveChanges();
    this.created(`/posts/${post.id}`, { data: post });
  }
}

// backend/server.js (excerpt)
master.addScoped('db', AppContext);
master.useHealthChecks({ checks: { database: { check: () => master.useScope((s) => s.db.canConnect()), tags: ['ready'] } } });
master.useOpenApi({ ui: '/docs' });
master.auth.addJwtBearer('bearer', { secret: config.get('Auth:JwtSecret') });
ASP.NET Core
ASP.NET Core
// Controllers/PostsController.cs
[ApiController]
[Route("posts")]
public class PostsController : ControllerBase
{
    private readonly AppDbContext _db;                // scoped DbContext
    public PostsController(AppDbContext db) => _db = db;

    [HttpGet]
    public async Task<IActionResult> Index() =>
        Ok(new { data = await _db.Posts.ToListAsync() });

    [HttpGet("{id:int}")]
    public async Task<IActionResult> Show(int id)
    {
        var post = await _db.Posts.FindAsync(id);
        return post is null ? NotFound("Post not found") : Ok(new { data = post });
    }

    [Authorize]
    [HttpPost]                                        // invalid body -> 400 ValidationProblemDetails
    public async Task<IActionResult> Create(PostDto dto)
    {
        var post = new Post { Title = dto.Title };
        _db.Posts.Add(post);
        await _db.SaveChangesAsync();
        return Created($"/posts/{post.Id}", new { data = post });
    }
}

// Program.cs (excerpt)
builder.Services.AddDbContext<AppDbContext>();
builder.Services.AddHealthChecks().AddDbContextCheck<AppDbContext>(tags: new[] { "ready" });
builder.Services.AddOpenApi();
builder.Services.AddAuthentication().AddJwtBearer();
Honest accounting

Where the two genuinely differ

The programming model is now close enough that an ASP.NET developer can read a Master controller without a glossary. What does not translate one-to-one:

  • Language and typing. C# is statically typed end to end; a Master backend is plain ESM JavaScript (TypeScript is optional, and the scaffold uses it only on the Next.js side). Validation happens at the boundary (static schemas), not in the compiler.
  • Querying. EF Core has LINQ and IQueryable composition; MasterRecord uses string/arrow-function lambdas with $$ parameters plus explicit builders (include, thenInclude, groupBy().aggregate()) and ctx.query() for raw SQL. See MasterRecord vs Entity Framework.
  • Ecosystem. .NET has Microsoft-maintained libraries for almost everything and an ecosystem of the same size; Master leans on npm — bigger, but less uniform.
  • UI stacks. Razor Pages, Blazor and view components have no equivalent in Master — the UI is a Next.js app, by design. MasterController does have server-side view engines, but they are not the primary path.
  • gRPC and SignalR specifics. Master has no gRPC story. Real-time is Socket.IO socket controllers, not SignalR hubs (no built-in backplane, no .NET client).
  • Identity UI.The primitives are there (password hasher, tokens, cookie and bearer schemes, policies) but there is no generated user-management UI like ASP.NET Identity’s.
  • Raw throughput. The CLR and AOT compilation are faster than V8 for CPU-bound work; for typical I/O-bound APIs both are more than fast enough.
The verdict

Which should you choose?

Choose Master if your team is in the JavaScript/Node ecosystem, wants a React (Next.js) frontend as a first-class citizen, and still wants the ASP.NET-style structure — scoped DI, validated models, ProblemDetails, policies, configuration layers, health checks, OpenAPI and an in-process test host — without assembling it from a dozen packages.

Choose ASP.NET Coreif you are invested in C#/.NET, need compile-time typing across the whole stack, LINQ, gRPC, SignalR or Blazor, want the CLR’s raw performance, or run on Microsoft infrastructure.