< Summary - Heimdall API

Information
Class: ArturRios.Heimdall.WebApi.Binding.ModelBindingConfiguration
Assembly: ArturRios.Heimdall.WebApi
File(s): /home/runner/work/heimdall-api/heimdall-api/src/Presentation/ArturRios.Heimdall.WebApi/Binding/ModelBindingConfiguration.cs
Line coverage
100%
Covered lines: 3
Uncovered lines: 0
Coverable lines: 3
Total lines: 52
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage
100%
Covered methods: 1
Fully covered methods: 1
Total methods: 1
Method coverage: 100%
Full method coverage: 100%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Configure(...)100%11100%

File(s)

/home/runner/work/heimdall-api/heimdall-api/src/Presentation/ArturRios.Heimdall.WebApi/Binding/ModelBindingConfiguration.cs

#LineLine coverage
 1using System.Text.Json.Serialization;
 2using Microsoft.AspNetCore.Mvc;
 3using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
 4
 5namespace ArturRios.Heimdall.WebApi.Binding;
 6
 7/// <summary>
 8///     Model-binding configuration shared by the running API and the OpenAPI document generator.
 9///
 10///     Both call <see cref="Configure" /> for the same reason they both call
 11///     <c>SwaggerConfiguration.Configure</c>: tools/ArturRios.Heimdall.OpenApiGen builds its own
 12///     <c>AddControllers()</c> rather than using <c>Startup</c>, so configuration registered in only
 13///     one of the two would let the published document disagree with the API it documents.
 14/// </summary>
 15public static class ModelBindingConfiguration
 16{
 17    public static void Configure(MvcOptions options)
 18    {
 89919        options.ModelMetadataDetailsProviders.Add(new ServerPopulatedBindingMetadataProvider());
 20
 21        // With nullable reference types on, MVC infers [Required] on every non-nullable string or
 22        // collection property, so a JSON null would invalidate ModelState and MalformedRequestFilter
 23        // would answer the generic "The request is malformed." before the handler runs — hiding the
 24        // field's own message ("Secret is required.") and skipping the refused-write audit entry
 25        // (NFR-09). FluentValidation owns required-ness; the filter means only "cannot be bound".
 89926        options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true;
 89927    }
 28}
 29
 30/// <summary>
 31///     Makes a <c>[JsonIgnore]</c> property non-bindable, so a value arriving in the query string
 32///     cannot reach it and ApiExplorer does not publish it as a parameter.
 33///
 34///     The commands and queries the mediator takes as input double as the wire DTOs, so a property
 35///     the controller assigns from the route or the authenticated caller looks, to the framework,
 36///     exactly like one the client sends. <c>[JsonIgnore]</c> marks the difference: it already
 37///     excludes the property from a <c>[FromBody]</c> payload and its schema, and this provider
 38///     extends the same statement to the <c>[FromQuery]</c> path, where System.Text.Json attributes
 39///     otherwise mean nothing. <c>IsBindingAllowed = false</c> is what <c>[BindNever]</c> sets;
 40///     <c>[BindNever]</c> itself is unavailable to the Application-layer projects these DTOs live
 41///     in, which have no reference to the ASP.NET Core shared framework.
 42/// </summary>
 43public class ServerPopulatedBindingMetadataProvider : IBindingMetadataProvider
 44{
 45    public void CreateBindingMetadata(BindingMetadataProviderContext context)
 46    {
 47        if (context.Attributes.OfType<JsonIgnoreAttribute>().Any())
 48        {
 49            context.BindingMetadata.IsBindingAllowed = false;
 50        }
 51    }
 52}