Class ValueObjectEndpointConventionBuilderExtensions
Namespace: AdCodicem.ValueObjects.AspNetCore.Http
Assembly: AdCodicem.ValueObjects.AspNetCore.Http.dll
Answers a value object a minimal API endpoint could not bind with problem details carrying the code of the rule it broke.
public static class ValueObjectEndpointConventionBuilderExtensions
Inheritance
object ← ValueObjectEndpointConventionBuilderExtensions
Inherited Members
object.Equals(object?), object.Equals(object?, object?), object.GetHashCode(), object.GetType(), object.MemberwiseClone(), object.ReferenceEquals(object?, object?), object.ToString()
Methods
WithValueObjectProblemDetails<TBuilder>(TBuilder)
Answers a value object these endpoints could not bind with problem details carrying the code of the rule it broke.
public static TBuilder WithValueObjectProblemDetails<TBuilder>(this TBuilder builder) where TBuilder : IEndpointConventionBuilder
Parameters
builder TBuilder
The endpoints to cover.
Returns
TBuilder
The same builder, so calls can be chained.
Type Parameters
TBuilder
The builder: a route group, one endpoint, or any other convention builder.
Remarks
A minimal API refuses a value object it cannot bind with a 400 that says nothing of why. On the endpoints this
covers, the refusal is answered with the validation problem MVC writes, errors holding the message of each
rule a value broke, and TryParse the binder ran. A route value, a query value and a header
are covered, under the name they bind from, which [FromRoute], [FromQuery] and [FromHeader]
may set; so are the members of an [AsParameters] type and an array of value objects read from the query
string, whose refused elements are listed under its name with the code of the first. A required value object
that is absent is reported with
A filter is added to each endpoint whose handler may bind a value object from text. When it runs, it reads one
thing, the status the binder left: anything but a 400 goes on untouched, and only a refusal pays for the second
parse. A 400 that no value object caused, a refused
Empty text follows the binder that ran. The reflection-based binding parses it, so that ?country= for a
CountryCode? is reported with the rule that refused it. The Request Delegate Generator refuses no empty
query text: it binds null to a nullable value object, and the default instance, which no rule
has checked, to one that cannot be null, an array element included, so that nothing is reported
there. It takes an empty header for an absent one, reported with
The binder refuses a request body before any filter runs, and the framework answers it itself. With
RouteHandlerOptions.ThrowOnBadRequest on, the default in Development, the binder throws instead, before
the filter runs, and the exception handler registered by
AddValidation(), whose filter runs before every other, a request that also breaks a
DataAnnotations rule is answered with that rule alone.
The filter closes the check of each value object over its type through the descriptor's visitor, so that it runs
in a native binary. Under native AOT, a value object nothing registered, one written by hand or a construction of
a generic one, cannot be described there, and its refusal is left unexplained: register it as the JSON package
asks, ValueObjectRegistry.Register<TSelf, TValue>(TSelf.Schema) for one written by hand, with its
generated converter for a construction.
The response is written with the HTTP JSON options, which, without reflection-based serialization, as in a native
binary, know a type only through a serializer context: register AddProblemDetails(), which chains the
framework's own for problem details into them. Without it, or a context of the application's listing
HttpValidationProblemDetails and JsonElement, the covered endpoints fail to build, when the first
request needs them, with an
The messages are the English ones of the rules.
Exceptions
builder is null.
WithValueObjectProblemDetails<TBuilder>(TBuilder, Action<ValueObjectMessageOptions>)
Answers a value object these endpoints could not bind with problem details carrying the code of the rule it broke, and the message the application's resource gives that code.
public static TBuilder WithValueObjectProblemDetails<TBuilder>(this TBuilder builder, Action<ValueObjectMessageOptions> configure) where TBuilder : IEndpointConventionBuilder
Parameters
builder TBuilder
The endpoints to cover.
configure Action<ValueObjectMessageOptions>
Names the resource the messages are read from, through
Returns
TBuilder
The same builder, so calls can be chained.
Type Parameters
TBuilder
The builder: a route group, one endpoint, or any other convention builder.
Remarks
The endpoints are covered as errors holds, for each refused member, the message the resource holds under the key of the rule's code,
ValueObject.value_object.out_of_range, looked up after ValueObject.value_object.out_of_range.minimum
or .maximum for a type declaring one bound alone. It is formatted with the name the member binds from as
{0}, the name of the value object for a request body, whose JSON path may hold a refused dictionary key, and
the arguments the type's rules supply from {1}: a length, both bounds, the known values. The codes under
The resource is read through the request's IStringLocalizerFactory: register
builder.Services.AddLocalization(), without which a refusal throws an app.UseRequestLocalization(), so that the request chooses the culture. The current UI culture
chooses the template and the current culture formats the arguments. The exception handler that answers with
ThrowOnBadRequest on runs in the request's culture, whatever the order of UseRequestLocalization()
and UseExceptionHandler(). A template quoting an argument its code does not supply throws its
The options belong to the endpoint: covered twice, through a route group and the endpoint itself, it takes those of the convention that runs last, the endpoint's own over its group's, and a call without options keeps the other's.
Exceptions
builder or configure is null.