Repository navigation
Getting Started Partie
Partie connects typed query and command handlers to routes. Handler contracts describe the request and response types, and framework engines connect those handlers to various consuming frameworks.
Install Brigade.Net.Partie in the project that you want to handle your business logic:
dotnet add package Brigade.Net.PartieBrigade.Net.Partie provides the request binding attributes and handler contracts.
For an ASP.NET Core API, install these packages:
dotnet add package Brigade.Net.Partie.AspNetCore
dotnet add package Brigade.Net.Partie.Engines.AspNetCoreBrigade.Net.Partie.AspNetCore provides route declarations and HTTP binding.
Brigade.Net.Partie.Engines.AspNetCore generates the route attributes for your handlers and the helper that registers them with ASP.NET Core.
var app = builder.Build();
...
// Make Partie routes available to HTTP requests.
app.UsePartieRoutes();[PartieSystemBundle]
[AspNetSystemBundle]
[BrigadeGroup("/api/v1")]
public static partial class RoutingV1
{
}[FromPath] reads the course ID from the URL. The handler returns a course with that ID.
public sealed class CourseSearchQuery
{
[FromPath]
public required int CourseId { get; init; }
}
public sealed record CourseSearchResult(int CourseId, string Title);public sealed class CourseSearchHandler : IQueryHandler<CourseSearchQuery, CourseSearchResult, Unit>
{
public static async Task<Result<CourseSearchResult>> RunAsync(
Unit context,
CourseSearchQuery query,
CancellationToken cancellationToken
)
{
...
}
}[PartieSystemBundle]
[AspNetSystemBundle]
[BrigadeGroup("/api/v1")]
public static partial class RoutingV1
{
// GET /api/v1/courses/{courseId}
[CourseSearchHandlerRoute.Get("/courses/{courseId}")]
public static partial void Search();
}Use Unit when there is no value to pass or return. A handler with Unit as its context needs no extra context object. A command with Unit as its result completes without returning a response value.
Result holds either a value of type T or a failure such as NotFound or Conflict. Result pattern is designed to avoid the common "Use Exceptions as GOTO statement" antipattern many developers tend to fall for in C#.
UnitOfWork groups changes to transactional resources into one operation. If a command succeeds, Partie commits those changes; if it fails or throws, Partie rolls them back.
Both Providers and Parties can provide values to a handler’s context. For example, [UnitOfWorkPartie] provides a UnitOfWork to command handlers.
A Provider runs on demand when a handler or Partie asks for its value. For example, a handler can request the current academic year when it needs to choose the right course offering.
A Partie runs for every matching request, whether or not another part asks it for a value. The LogCourseSearchPartie below, for example, logs each matching course search.
Queries use IQueryProvider<TProvided, TContext, TQuery, TResult> and IQueryPartie<TProvided, TContext, TQuery, TResult>. Commands use ICommandProvider and ICommandPartie. Implement OnQueryAsync or OnCommandAsync; invoke next(value) to continue with the value you provide.
public sealed class AcademicYearProvider :
IQueryProvider<string, Unit, CourseSearchQuery, CourseSearchResult>
{
public static ValueTask<Result<CourseSearchResult>> OnQueryAsync(
Unit context,
CourseSearchQuery query,
Next<string, CourseSearchResult> next,
CancellationToken cancellationToken)
{
return next("2026-2027");
}
}public sealed class LogCourseSearchPartie :
IQueryPartie<Unit, Unit, CourseSearchQuery, CourseSearchResult>
{
public static async ValueTask<Result<CourseSearchResult>> OnQueryAsync(
Unit context,
CourseSearchQuery query,
Next<Unit, CourseSearchResult> next,
CancellationToken cancellationToken)
{
Console.WriteLine($"Searching for course {query.CourseId}");
return await next(Unit.Default);
}
}Add [Provide] to a context parameter to receive the value created by a provider:
public sealed record CourseSearchContext([Provide] string AcademicYear);
public sealed class CourseSearchHandler :
IQueryHandler<CourseSearchQuery, CourseSearchResult, CourseSearchContext>
{
public static Task<Result<CourseSearchResult>> RunAsync(
CourseSearchContext context,
CourseSearchQuery query,
CancellationToken cancellationToken)
{
// Use context.AcademicYear to choose the course offering.
...
}
}[Provide] requests the value from [AcademicYearProvider].
Add your custom created Providers and Parties via their automatically generated attributes:
[AcademicYearProvider]
[LogCourseSearchPartie]
[CourseSearchHandlerRoute.Get("/{courseId}")]
public static partial void Search();Use [Inject] when a handler context needs a service registered with the framework’s dependency injection system. IE ASP.NET Core's builder.Services:
builder.Services.AddScoped<ICourseCatalog, CourseCatalog>();
...
public sealed record CourseCatalogContext([Inject] ICourseCatalog Catalog);Use the [PartieSystemBundle] on the root grouping, it includes the UnitOfworkPartie automatically.
Automatically configures commit and rollback of the UnitOfWork system within Partie, which broadly allows for transactional behaviors.
For an ASP.NET Core API, use [AspNetSystemBundle] on the root route group. It includes HttpResultPartie automatically.
Automatically maps Result types back to Http Status codes
Success: 200 OK, or 204 No Content for Unit
Deprecated: Same status as success, with a Deprecation response header and expiry
Error: The status set on the error, or 400 Bad Request by default
NotFound: 404 Not Found
Conflict: 409 Conflict
Forbidden: 403 Forbidden
GatewayError: 502 Bad Gateway
Timeout: 504 Gateway Timeout
Check out installing the Expo system for Validation, and Mise system for Database ORM integration!
See the Partie guide for request binding, services, providers, Parties, and policies. The Example project shows handlers with application services and route policies.
- Home
- Getting started
-
Package guides
- Partie
- Expo
-
Mise
- Database setup
- Table mappings
- Aliases
- Relationships
- Result rows
- SQL interpolation
- Queries
- Filtering
- Joins
- Aggregation
- Paging and ordering
- Subqueries
- Set operations
- Common table expressions
- Readers
- Streaming
- Writers
- Inserts
- Updates
- Deletes
- Returned rows
- Custom SQL and procedures
- Transactions
- Resource lifetimes
- Database dialects
- Diagnostics
- Integrations
- Recipes
- Reference
- Troubleshooting
- Development