Megaraz.ResultPattern.AspNetCore 0.1.3

dotnet add package Megaraz.ResultPattern.AspNetCore --version 0.1.3
                    
NuGet\Install-Package Megaraz.ResultPattern.AspNetCore -Version 0.1.3
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Megaraz.ResultPattern.AspNetCore" Version="0.1.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Megaraz.ResultPattern.AspNetCore" Version="0.1.3" />
                    
Directory.Packages.props
<PackageReference Include="Megaraz.ResultPattern.AspNetCore" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Megaraz.ResultPattern.AspNetCore --version 0.1.3
                    
#r "nuget: Megaraz.ResultPattern.AspNetCore, 0.1.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Megaraz.ResultPattern.AspNetCore@0.1.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Megaraz.ResultPattern.AspNetCore&version=0.1.3
                    
Install as a Cake Addin
#tool nuget:?package=Megaraz.ResultPattern.AspNetCore&version=0.1.3
                    
Install as a Cake Tool

Megaraz.ResultPattern.AspNetCore

HTTP and ASP.NET Core extensions for Megaraz.ResultPattern. The package maps core results to predictable HTTP response descriptors and provides optional MVC and minimal-API adapters.

The framework-agnostic mapper does not create endpoints, choose application messages, or impose a remote service's error schema. Applications own routing, authentication, localization, and any public API contract that differs from the documented defaults.

Supported frameworks

  • .NET 8
  • .NET 9
  • .NET 10

Installation

dotnet add package Megaraz.ResultPattern.AspNetCore

Mapping outbound results

Use the pure mapper when the application needs to control how the response is written:

var response = HttpResultMapper.ToHttpResponse(result);
return Results.Json(
    response.Body,
    statusCode: response.StatusCode,
    headers: response.Location is null
        ? null
        : new HeaderDictionary { ["Location"] = response.Location });

Successful typed results use 200 OK and place the value in the body. Successful non-generic results use 200 OK without a body. Created results use 201 Created and preserve an optional Location header. Commands can use ToNoContentResponse for 204 No Content.

Minimal APIs

app.MapGet("/accounts/{id}", (Guid id) =>
{
    Result<Account> result = service.Get(id);
    return result.ToHttpResult();
});

app.MapPost("/accounts", (CreateAccount request) =>
{
    Result<Account> result = service.Create(request);
    return result.ToCreatedHttpResult($"/accounts/{result.Value.Id}");
});

Use ToNoContentHttpResult for successful commands. These adapters write the status, body, and Location header while preserving the default failure body.

MVC controllers

[HttpGet("{id}")]
public ActionResult<Account> Get(Guid id)
{
    Result<Account> result = service.Get(id);
    return this.ToActionResult(result);
}

[HttpPost]
public ActionResult<Account> Create(CreateAccount request)
{
    Result<Account> result = service.Create(request);
    return this.ToCreatedResult(result, $"/accounts/{result.Value.Id}");
}

When an MVC controller has a route for the created resource, use the route-aware overload to produce a CreatedAtActionResult:

return this.ToCreatedResult(
    result,
    nameof(GetAccountById),
    account => new { id = account.Id });

Default response contract

Failure responses use immutable DTOs with camel-case JSON names. Codes are machine-readable public API identifiers; applications should version them deliberately and avoid changing a code's meaning after publishing.

Non-validation failure:

{
  "message": "Account was not found.",
  "code": "account.not_found"
}

Validation failure:

{
  "message": "One or more validation errors occurred.",
  "code": "validation.failed",
  "validationErrors": [
    {
      "field": "email",
      "message": "Email is required."
    },
    {
      "field": null,
      "message": "The request is invalid."
    }
  ]
}

validationErrors is a materialized list and is omitted for other failures. MappedHttpResponse.Body remains object? because successful values and custom failure factories may use application-defined DTOs.

Customizing mappings

Start with HttpResultMappingPolicy.Default and override only application specific rules:

var policy = HttpResultMappingPolicy.Default with
{
    SuccessStatusCode = StatusCodes.Status202Accepted,
    ErrorTypeStatusCode = errorType => errorType switch
    {
        ErrorType.Validation => StatusCodes.Status400BadRequest,
        _ => HttpResultMappingPolicy.Default.ErrorTypeStatusCode(errorType)
    },
    FailureBodyFactory = result =>
        new { error = result.Message, code = result.PrimaryError.Code }
};

return result.ToHttpResult(policy);

The policy supports separate selectors for core ErrorType and HttpErrorType, success statuses for ordinary, no-content, and created responses, and a failure-body factory. Supplying a custom failure factory makes the application responsible for that response contract.

Mapping inbound HTTP responses

HttpResponseMessage can be converted to a typed or non-generic result:

var result = await response.MapToResultAsync<Account>(context);

Successful JSON bodies are deserialized with web-default JsonSerializerOptions. Non-success responses become HttpError values. HttpError retains the core package's ErrorType.External classification and adds HTTP-specific categories such as TransportFailure, MalformedResponse, and UnexpectedStatusCode.

Response content is consumed. Both the default reader and streaming deserializer read at most 64 KiB by default; configure HttpResponseMappingOptions.MaxResponseBodyBytes for another limit. Use MapToResultWithDeserializerAsync when a successful payload should be streamed without buffering. Cancellation is propagated and is never converted to a failure.

Upstream response text is kept in the technical Error.Description; it is not copied to Error.UserMessage by default. Applications that intentionally proxy a vetted upstream message can opt in:

var options = new HttpResponseMappingOptions
{
    UserMessageFactory = message => IsSafeForClients(message) ? message : null
};

var result = await response.MapToResultAsync<Account>(context, options);

Pass JsonSerializerOptions to control successful-body deserialization and ErrorMessageExtractor when an upstream service uses a different error schema. HttpClient request, DNS, connection, and timeout exceptions are not caught by the response mapper; map selected exceptions explicitly in the surrounding catch block with MapTransportExceptionToResult.

Pagination

Normalize endpoint query values with an application-configured maximum:

var pagination = PaginationParameters.Normalize(page, pageSize, maxPageSize);

Page numbers are at least 1 and page sizes are clamped between 1 and the provided maximum. A maximum below 1 throws ArgumentOutOfRangeException.

Versioning

The package follows semantic versioning. Public response fields, error codes, and documented mapping defaults are compatibility-sensitive API. Breaking changes require a major version; new backward-compatible APIs and behavior use minor versions. Patch releases contain backward-compatible fixes.

License

This project is licensed under the MIT License.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.3 107 8/7/2026
0.1.2 349 8/2/2026
0.1.1 380 7/26/2026
0.1.0 110 7/25/2026

0.1.3: Hardens the release supply chain with CodeQL, dependency review, NuGet Dependabot updates, secret scanning push protection, and protected release checks.