Skip to content

Controller-based queries

Use a controller when your query needs MVC routing, model binding, or authorization policies. Unlike a model-bound query, the method does not need to live on the type it returns.

This controller example uses the shared AccountId and AccountName concepts with an ASP.NET Core Arc host, MVC, and the configured Arc MongoDB provider. Use this DebitAccount declaration instead of the model-bound alternative. No Chronicle integration is required.

using System.Collections.Generic;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using MongoDB.Driver;
namespace Banking.Accounts;
public record DebitAccount(AccountId Id, AccountName Name, decimal Balance);
[Authorize(Roles = "AccountReader")]
[Route("api/accounts")]
public class AccountsController(IMongoCollection<DebitAccount> collection) : ControllerBase
{
[HttpGet]
public IEnumerable<DebitAccount> AllAccounts() => collection.Find(_ => true).ToList();
}

With authentication and authorization middleware configured, the MVC authorization attribute protects this action. Arc’s QueryActionFilter handles GET actions: it establishes query context, processes MVC model-state errors, renders the returned data, applies interception, and wraps it in QueryResult.

This is not the model-bound IQueryPipeline filter chain. Do not assume model-bound custom filters run for a controller action, or that Arc’s GET query wrapper applies to a POST action.

The proxy generator creates client types from supported controller query declarations. For raw MVC responses, see without wrappers; opting out changes the contract a standard Arc query client expects.