This guide walks you through building your first MASA Framework microservice from scratch. You will set up a project with automatic route mapping viaDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/masastack/MASA.Framework/llms.txt
Use this file to discover all available pages before exploring further.
ServiceBase, an in-process EventBus, and EF Core data access — all wired together in a minimal Program.cs. The entire setup takes about five minutes.
Prerequisites
- .NET 6 SDK or later installed
- Basic familiarity with ASP.NET Core Minimal APIs
You can also create the project from Visual Studio by selecting the MASA Framework Project template in the New Project dialog. The template pre-configures EventBus, Minimal APIs, and a sample service class.
If you prefer to add MASA Framework to an existing ASP.NET Core project, install the three core packages:
Masa.Contrib.Dispatcher.Events[EventHandler] attribute scanningMasa.Contrib.Service.MinimalAPIsServiceBaseMasa.Contrib.Data.EFCore.SqlServerWire everything together in
Program.cs. The key calls are services.AddEventBus(), builder.AddServices() (which discovers all ServiceBase subclasses), and app.MapMasaMinimalAPIs() (which maps their routes):var builder = WebApplication.CreateBuilder(args);
// Register the in-process EventBus.
// AddEventBus() scans MasaApp.GetAssemblies() for [EventHandler] methods automatically.
builder.Services.AddEventBus();
// AddServices() scans all loaded assemblies for ServiceBase subclasses,
// registers them in DI, and returns the built WebApplication.
// This call must come last before app.Run().
var app = builder.AddServices();
// MapMasaMinimalAPIs() iterates every registered ServiceBase and calls
// AutoMapRoute(), translating method names to HTTP verbs and URL patterns.
app.MapMasaMinimalAPIs();
app.Run();
builder.AddServices() must be the last call on builder before app.Run(). Registering services after this call may not be reflected in the DI container.Service class — Inherit from
ServiceBase and pass a base URI to the constructor. Public methods whose names start with a recognised HTTP verb prefix (Get, Post, Put, Delete) are mapped automatically. The Async suffix and the verb prefix are stripped from the route segment.public class OrderService : ServiceBase
{
// All routes will be prefixed with /api/v1/orders
public OrderService() : base("/api/v1/orders") { }
// Mapped to: GET /api/v1/orders
public async Task<List<Order>> GetListAsync(
[FromServices] IOrderRepository repo)
=> await repo.GetListAsync();
// Mapped to: POST /api/v1/orders
public async Task CreateAsync(
[FromBody] CreateOrderCommand cmd,
[FromServices] IEventBus eventBus)
=> await eventBus.PublishAsync(cmd);
}
BaseUri — the route prefix set in the constructor.App — the WebApplication instance, resolved via MasaApp.Services — the global IServiceCollection.GetRequiredService<T>() — convenience wrapper over the request IServiceProvider.Event and handler — Declare a plain class that implements the command, then use
[EventHandler] to mark the handling method. AddEventBus() discovers this class automatically through assembly scanning:// The command event — inherits from the framework Event base
public record CreateOrderCommand(string Name) : Event;
// The handler class — no interface required, just [EventHandler]
public class OrderCommandHandler
{
[EventHandler]
public async Task HandleCreateAsync(
CreateOrderCommand cmd,
IOrderRepository repo)
=> await repo.AddAsync(new Order(cmd.Name));
}
Run the Service
https://localhost:<port>/api/v1/orders to verify the GET endpoint is live. Use a tool like curl or Postman to test the POST endpoint:
What Happens Under the Hood
How AddEventBus() scans for handlers
How AddEventBus() scans for handlers
AddEventBus() calls MasaApp.GetAssemblies() to obtain the loaded assembly list, then uses DefaultDispatchNetworkProvider to reflect over every type and find methods decorated with [EventHandler]. Each handler type is registered in DI at ServiceLifetime.Scoped by default. When IEventBus.PublishAsync<TEvent>() is called, the framework resolves the correct handler chain and executes it in declaration order (controlled by the Order property on the attribute).How AddServices() discovers ServiceBase classes
How AddServices() discovers ServiceBase classes
builder.AddServices() delegates to ServiceCollectionExtensions.AddServices(), which scans MasaApp.GetAssemblies() for all concrete types that inherit ServiceBase. Each discovered type is registered as a singleton in the DI container and its Type is recorded in GlobalMinimalApiOptions.ServiceTypes for use by MapMasaMinimalAPIs().How MapMasaMinimalAPIs() builds routes
How MapMasaMinimalAPIs() builds routes
MapMasaMinimalAPIs() iterates GlobalMinimalApiOptions.ServiceTypes, resolves each ServiceBase instance from the DI container, and calls serviceInstance.AutoMapRoute(). That method reflects over the public instance methods declared directly on the class and calls App.MapMethods() (or App.MapGet/Post/Put/Delete) for each one, deriving the HTTP verb and URL segment from the method name prefix.Next Steps
Architecture
Understand the full BuildingBlocks/Contrib two-layer design and MasaApp internals.
Event Bus
Explore middleware pipelines, saga handlers, retry policies, and failure levels.