Coding Style
Add this feature using AddCodingStyles() extension;
app.Features.AddCodingStyles([...]);
Add/Remove Child as Sub Resource
Configures method routes in AddChild and RemoveChild(Child) signature to
have a resource route POST /../children and DELETE /../children/{childId}
respectively.
c => c.AddRemoveChildAsSubResource()
Command via Method Name
Uses class names as route and removes configured method names from route.
c => c.CommandViaMethodName(methodNames: [...])
Default value of
methodNamesis["Execute", "Process"].
Extension via Locatable Initializer
Allows classes to extend locatables via composition. This marks a transient
class as a locatable extension when it has a property with IdProperty
attribute and an initializer with only one parameter that is a locatable.
Methods of these extension classes are rendered under locatable group.
c => c.ExtensionViaLocatableInitializer()
Flags Enum
Adds support for enums marked with [Flags]. Configures data access to map
flags enum properties, including nullable ones, using the enum type itself, and
configures api serialization to represent them as an array of flag names in
camelCase.
c => c.FlagsEnum()
To create a flags enum, mark it with [Flags] and give each member a distinct
bit;
[Flags]
public enum Permissions
{
Read = 1 << 0,
Write = 1 << 1,
Delete = 1 << 2
}
A property of this type is serialized as below, and is deserialized from the same representation;
["read", "write"]
Initializable via Method Name
Adds Transient attribute to the services that has a method with Initializer
attribute. This coding style makes usages like _newEntity().With(name)
possible. Initializer parameters of a type with Transient attribute are added
to query string and initializer is invoked with given parameters when
constructing target.
c => c.InitializableViaMethodName(initializerNames: [...])
Default value of
initializerNamesis["With"].
Locate via ID
Manages binding of targets and api inputs that have Locatable attribute. For
such types, this feature adds id parameter to route, configures finding target
and parameter lookup expressions by using Locatable attribute.
c => c.LocateViaId()
Parameter lookup is only supported for types with
Locatableattribute
A locatable does not get an endpoint to fetch it by its id, e.g.,
GET /todos/{id}, unless it is added explicitly with below extension;
configurator.Domain.ConfigureConventions(conventions =>
{
conventions.AddLocateAction<Todo>();
});
Name based Label
Marks selected string properties as labels by giving Label attribute to
properties with matching names.
c => c.NameBasedLabel(propertyNames: [...])
Default value of
propertyNamesis["Display", "Label", "Name", "Title"].
Namespace as Route
Reflects namespace of a domain class as base route for its endpoints.
c => c.NamespaceAsRoute()
Object as JSON
Configures all object parameters, return types and properties to be treated as
JSON content.
c => c.ObjectAsJson()
Primitive via Parsable
Allows creating custom primitives via IParsable<T> interface. It marks these
types as Primitive attribute and maps them using PrimitiveUserType in data
access layer using NHibernateUtil.String. Allows serializing and deserializing
to and from string in json and API endpoints.
c => c.PrimitiveViaParsable()
To create a primitive implement IParsable<> and override ToString(). Below
is an example implementation;
public readonly record struct MyValue : IParsable<MyValue>
{
public static MyValue Parse(string s, IFormatProvider? provider)
{
if (!TryParse(s, provider, out var result))
{
throw new FormatException($"'{s}' is not in an expected format");
}
return result;
}
public static bool TryParse(
[NotNullWhen(true)] string? s,
IFormatProvider? provider,
[MaybeNullWhen(false)] out MyValue result
)
{
// Add your custom validation and parse logic here
result = new(s ?? string.Empty);
return true;
}
readonly string _data;
MyValue(string data)
{
_data = data;
}
public override string ToString() =>
_data;
}
Query via Plural Name
Adds Query attribute to the classes that has plural name of a locatable class,
e.g. assuming MyLocatable is a locatable, MyLocatables becomes a query.
Removes FirstBy, SingleBy and By names from API routes and configure them
as GET endpoints.
Adds QueryMethod attribute to the methods having given name of types with
Query attribute and marks parameters with Sorting and Paging attributes.
c => c.QueryViaPluralName(
queryMethodNames: [...],
primaryParameterNames: [...],
takeParameterNames: [...],
skipParameterNames: [...],
sortingParameterNames: [...]
)
Default values for parameters are listed below;
queryMethodNames:["By"]primaryParameterNames:["searchText"]takeParameterNames:["take"]skipParameterNames:["skip"]sortParameterNames:["sort"]
A class that injects
IQueryContextis not considered as a query class unless it satisfies the plural naming convention.
Records are DTOs
Configures domain type records as valid input parameters. Methods containing record parameters render as api endpoints.
c => c.RecordsAreDtos()
Validation attributes of a record are only validated when they target its properties. Attributes given to primary constructor parameters are ignored without any error.
// ignored public record MyRecord([Range(1, 10)] int Value); // validated public record MyRecord([property: Range(1, 10)] int Value);
Remaining Services are Singleton
Adds Singleton attribute to the services that has no Transient or Scoped
attributes.
c => c.RemainingServicesAreSingleton()
Resource via ID Initializer
Configures transient services as api services. This coding style marks a type
having a public initializer with a single Business.Id parameter which will
render from route, as Resource attribute, configures Locatable attribute and
generates locators.
Resources can be method parameters and located using their locators.
Configures routes and swagger docs to use entity methods as resource actions.
c => c.ResourceViaIdInitializer()
Rich Entity
Adds Entity attribute to classes that inject IEntityContext<TEntity>.
Configures NHibernate to initialize entities using dependency injection,
making them rich entities.
Configures routes and swagger docs to use entity methods as resource actions.
c => c.RichEntity()
Status Enum via Suffix
Adds Status attribute to enum properties with the enum name ending with
Status. It also configures Severities using enum values using table below.
c => c.StatusEnumViaSuffix()
| Range | Severity |
|---|---|
| 100-199 | info |
| 200-299 | success |
| 400-499 | warn |
| 500-599 | danger |
Below is an example status enum;
public enum RecordStatus
{
Draft = 000,
Preparing = 100, // info
Ready = 101, // info
Sent = 200, // success
SentWithIssues = 400, // warn
NeedsRevision = 401, // warn
NotSent = 500 // danger
}
Scoped via Suffix
Adds Scoped attribute to the services that has name with any of the given
suffixes.
c => c.ScopedViaSuffix(suffixes: [...])
Default value of
suffixesis["Context"].
Suffix based Client
Configures IXxxClient interfaces as outgoing clients and removes rest binding
for their implementations. Also, adds singleton mock override for the interface
to inject mock instances to domain objects that use client interfaces.
c => c.SuffixBasedClient()
Type based ID
This feature provides Id configuration for transient and entity classes.
c => c.TypeBasedId()
Single property of type Baked.Business.Id is marked with IdProperty
attribute. For entities, Id properties are mapped with IdGuidUserType and
generated with IdGuidGenerator using DbType.Guid.
public class Entity(IEntityContext<Parent> _context)
{
public Id Id { get; private set; } = default!;
...
}
To override ID mapping of an entity, add a property attribute configuration on
IdPropertyattribute as below,conventions.EditPropertyAttribute<IdProperty>( when: c => c.Type.Is<MyEntity>(), attribute: id => id.Assigned() // or id.AutoIncrement() );
Unique via SingleBy
Adds Unique attribute to entity properties of which corresponding query class
has a SingleBy... query method, e.g., User.Username property would be
treated as unique if Users.SingleByUsername exists.
c => c.UniqueViaSingleBy()
Having
Uniqueattribute on a property tellsAutoMapOrmFeatureto configure that column to have a unique constraint.
Uri Return is Redirect
Adds redirect support to your api endpoints. It configures an endpoint to use
redirect result when its corresponding method returns Uri. Combined with
CommandViaMethodName, it allows you to create callback GET endpoints when
method doesn't have any parameters. For actions that have parameters, it
configures its corresponding endpoint to accept form instead of a json body.
c => c.UriReturnIsRedirect()
Use Built-in Types
Configures built-in .NET types to be used as entity properties and service
parameters. Uses IParsable<> interface to configure primitives. Additionally
configures string, enums, Uri and IEnumerable<> types.
It also allows for string properties to use TEXT column type instead of
VARCHAR by suffixes.
c => c.UseBuiltInTypes(textPropertySuffixes: [...])
Default value of
textPropertySuffixesis["Data", "Description"].
Use Nullable Types
Adds support for nullable value and reference types. Configures api model to forbid sending null or empty values to not-null parameters.
c => c.UseNullableTypes()