Skip to content

Attribute reference

Arc discovers what your application exposes from attributes on your own types. This is the whole set you write, grouped by what it concerns. Attributes that come from Chronicle or Fundamentals rather than Arc are marked as such, because they arrive with a different package.

For the Kotlin and Java equivalents, see its annotation reference — the concepts match, the spellings do not.

AttributeValid onEffect
[Command]classMarks a record or class as a command. Arc exposes it, validates and authorizes it, and calls its Handle() method.
[ReadModel]classMarks a type as a read model. Eligible public or internal static methods become queries; private helpers do not.
[Command]
public record RegisterAuthor(AuthorId Id, AuthorName Name)
{
public Task Handle(IMongoCollection<Author> authors) =>
authors.InsertOneAsync(new Author(Id, Name));
}
AttributeValid onEffect
[Path] (Cratis.Arc.Queries.ModelBound)model-bound command, read model or query methodOverrides the conventional HTTP route. A command’s /validate endpoint uses the same path plus /validate. The explicit path is not prefixed or lowercased.
[QueryHttpMethod]read model, query methodSets the HTTP method the generated proxy uses by default (GET, QUERY, or Auto). The server accepts GET and, unless GeneratedApis.EnableQueryHttpMethod is false, QUERY regardless of this attribute.
[FromRequest]parameter, propertyBinds a value from several request sources rather than the default one.
[ExplicitOffset] (Cratis.Arc.Commands)property, fieldRequires JSON DateTime/DateTimeOffset input to include an explicit offset or Z. Nullable forms accept null. Use [property: ExplicitOffset] on a positional record; see input binding.

A route you do not override is derived, so [Path] is for the cases where the derived route is wrong for you — not something to apply everywhere. A command’s explicit [Path("/api/orders/create")] stays stable even if another command is added to its namespace; its generated TypeScript proxy calls that same path. Import Cratis.Arc.Queries.ModelBound for both commands and queries. A command’s path must be declared on that command type, not inherited from a base type. Avoid reusing an explicit path for another command or for a conventional command route; route collisions can make endpoints ambiguous. A command path is a literal route: route templates such as {id} are not supported for commands, and it should not end with / (the validation endpoint appends /validate).

AttributeValid onEffect
[ExcludeFromDiscovery] (Cratis.Arc)command type, read model type, query method, controller or controller actionOmits the marked operation from /.cratis/commands or /.cratis/queries and generated OpenAPI descriptions (including command validation endpoints).

The marker is inherited: marking a base command type or read model also hides every type that derives from it. This differs from a command’s [Path], which is not inherited.

This marker does not unmap the HTTP endpoint or authorize it. Protect it with [Authorize], a trusted ingress, or both; do not rely on hiding metadata as a security boundary. Controller-based commands are not in the command catalog, but marked controller actions are omitted from MVC’s API descriptions.

AttributeValid onEffect
[Authorize]class, methodRequires an authenticated caller, optionally satisfying a policy.
[Roles]class, methodRequires at least one of the listed roles.
[AllowAnonymous]class, methodOpens a specific artifact or operation back up.

Apply them at class level to cover everything and override per method for the exceptions. An artifact with no authorization attribute is open to any caller unless your ASP.NET Core host configures a fallback policy, so protection is something you declare, not a default. A failure surfaces as isAuthorized: false in the result rather than as an exception, so the frontend can react to it.

AttributeValid onEffect
[IgnoreValidation]controller, actionSkips Arc’s validation filter for an ASP.NET Core controller or action, leaving ASP.NET Core’s default model validation behavior. It has no effect on model-bound commands and queries.

Most validation is declared in a CommandValidator<T> or ConceptValidator<T> rather than with an attribute. See validation.

AttributeValid onEffect
[IgnoreAutoRegistration]classKeeps a type out of Arc’s conventional discovery.
[AspNetResult]controller, actionReturns an ASP.NET Core controller action’s result directly instead of wrapping it in Arc’s result envelope. It applies to controller-based endpoints only.

[AspNetResult] opts out of the envelope the generated client expects, so a proxy will not consume that endpoint in the usual way. Reach for it when an endpoint exists for something other than your own frontend.

These arrive with Chronicle rather than Arc itself, and only apply when the Chronicle integration is in use.

AttributeValid onEffect
[EventType]classMarks a record as an event. Takes no arguments for a new event.
[Key] (Cratis.Chronicle.Keys)property, positional record parameterIdentifies the event source a command acts on. Without Chronicle, Arc instead reads System.ComponentModel.DataAnnotations.KeyAttribute as the command key; Chronicle ignores that one, so unless the command has an EventSourceId-typed property, it can silently resolve no event source; ARCCHR0008 warns about it.
[NotAudited]class, struct, property, parameterKeeps a secret out of the causation chain written with every event.
[ExecuteCommandsAsSystem]classRuns a reactor’s returned commands without a user principal.

[NotAudited] is the one worth knowing before you need it: a command’s property values are recorded in the causation chain of every event it appends, so an unmarked token or password reaches the event log in clear text and stays there. It is not interchangeable with Chronicle’s [PII], which encrypts and enrolls a value in erasure — that is the right marking for personal data and the wrong one for a secret.

  • Code analysis — the analyzers that check these are used correctly.
  • Commands and Queries — what the artifact attributes actually enable.