Controller Based Queries
You can represent queries as regular ASP.NET Core Controller actions with HTTP GET methods.
public record DebitAccount(AccountId Id, AccountName Name, CustomerId Owner, decimal Balance);
[Route("api/accounts")]
public class Accounts : Controller
{
readonly IMongoCollection<DebitAccount> _collection;
public Accounts(IMongoCollection<DebitAccount> collection) => _collection = collection;
[HttpGet]
public IEnumerable<DebitAccount> AllAccounts() => _collection.Find(_ => true).ToList();
}
Note: This particular model represents its values as concepts - a value type encapsulation that makes us not use primitives - thus creating clearer APIs and models.
Note: If you're using the Cratis Arc proxy generator, the method name will become the query name for the generated TypeScript file and class.
Key Features
Controller-based queries provide several powerful features:
- Standard ASP.NET Core routing and HTTP verb support
- Flexible return types including collections, single objects, and custom response wrappers
- Dependency injection for services and repositories
- Query arguments via route parameters, query strings, and request bodies
- Async support for asynchronous operations
- Observable queries for real-time data streaming
- Custom route templates for RESTful API design
When to Use Controller-Based Queries
Controller-based queries are ideal when you:
- Want explicit control over HTTP routing and URL structure
- Need to leverage existing ASP.NET Core features like filters, middleware, or custom attributes
- Are building RESTful APIs with standard HTTP conventions
- Want to separate query logic from your read models
- Need complex routing scenarios with multiple parameters
Bypassing Query Result Wrappers
By default, controller-based queries return results wrapped in a QueryResult structure. If you need to return the raw result from your controller action without this wrapper, you can use the [AspNetResult] attribute. For more details, see Without wrappers.
Related Topics
- Route Templates - Learn about URL routing and parameter binding
- Query Arguments - How to handle different types of query parameters
- Return Types - Understanding different response formats
- Observable Queries - Real-time data streaming with WebSockets
- Dependency Injection - Working with services and repositories
Basic Example with Async Support
For asynchronous operations, you can return Task<T>:
[HttpGet]
public async Task<IEnumerable<DebitAccount>> AllAccountsAsync()
{
var result = await _collection.FindAsync(_ => true);
return result.ToList();
}
Note: The proxy generator automatically creates TypeScript types for your controller methods, making them strongly typed on the frontend as well.