RA.Utilities.Core.Constants
A centralized and consistent set of core values for the RA.Utilities ecosystem.
It replaces magic strings and magic numbers with named read-only fields and a semantic ResponseType enum, giving every service a single source of truth for HTTP codes, messages, header names, and validation errors.
🎯 Purpose
The primary goal of this package is to ensure consistency across different projects and services. By using these predefined values, you can:
- Avoid Typos: Prevent hard-to-find bugs caused by typos in strings or numbers.
- Improve Readability: Make your code more self-documenting (e.g.,
BaseResponseCode.NotFoundis clearer than404). - Simplify Maintenance: Update a value in one place, and the change propagates everywhere it's used.
- Stay Consistent: Every service in the ecosystem reports the same status code and wording for the same outcome.
✨ Key Features
- HTTP Status Codes —
BaseResponseCodeexposes namedintfields for all common HTTP status codes (200–504) - Standardized Messages —
BaseResponseMessagesdelivers consistent, production-ready API response text - Validation Error Codes & Messages —
BaseErrorCodeandBaseErrorMessagestandardize field-level validation failures (email, currency, money, SSN, IBAN) - Semantic Response Types —
ResponseTypeis an enum for API outcome classification; its numeric values are stable and serializable - HTTP Header Names —
HeaderParameterscentralizes common header names for tracing, auth, and location - Patchable Values — fields are
static readonly(notconst), so a corrected value ships in a package update without recompiling every consumer - Zero Dependencies — No external package dependencies; pairs seamlessly with
RA.Utilities.Core.Exceptions - No Configuration — No DI registration, no options, and no setup required
v10.0.4 made two breaking changes: every field moved from const to static readonly, and ResponseType became a plain enum. The values themselves are unchanged. Later releases are purely additive: v10.0.5 adds four IBAN validation codes and messages, and v10.1.1 adds PaymentRequired (402) to BaseResponseCode, BaseResponseMessages, and ResponseType. See the Migration Guides before upgrading.
🛠️ Getting Started
Prerequisites
- .NET 10.0 or later
Installation
.NET CLI
dotnet add package RA.Utilities.Core.Constants
Package Manager Console
Install-Package RA.Utilities.Core.Constants
PackageReference (csproj)
<PackageReference Include="RA.Utilities.Core.Constants" Version="10.1.1" />
Hello World
The simplest possible usage — replace a magic number with a named value:
using RA.Utilities.Core.Constants;
// Before: magic number
return StatusCode(404, "The requested resource was not found.");
// After: self-documenting values
return StatusCode(BaseResponseCode.NotFound, BaseResponseMessages.NotFound);
No DI registration, no setup, no configuration. Just add the using directive and reference the values.
🧠 Core Concepts
The package provides six types, each serving a distinct role in your API layer:
| Type | Role | Example |
|---|---|---|
BaseResponseCode | HTTP status codes as static readonly int fields | BaseResponseCode.NotFound → 404 |
BaseResponseMessages | Human-readable response messages as static readonly string fields | BaseResponseMessages.NotFound → "The requested resource was not found." |
BaseErrorCode | Machine-readable validation error codes as static readonly string fields | BaseErrorCode.EmailRequired → "REQUIRED_EMAIL" |
BaseErrorMessage | Human-readable validation error messages as static readonly string fields | BaseErrorMessage.EmailRequired → "The 'Email address' field is required." |
ResponseType | Semantic outcome labels as an enum | ResponseType.NotFound → 8 (numeric value) |
HeaderParameters | HTTP header names as static readonly string fields | HeaderParameters.XRequestId → "x-request-id" |
Since v10.0.4, the constant holders expose static readonly fields rather than compile-time constants. You can read them anywhere, but you cannot use them where C# requires a constant expression — attribute arguments, default parameter values, case labels, or const declarations. (ResponseType is an enum, so its members remain constant expressions.) See Troubleshooting for workarounds.
How they work together
BaseResponseCode and BaseResponseMessages handle the transport-level concerns (what HTTP code and what message), while ResponseType adds a machine-readable semantic label inside the JSON response body. HeaderParameters ensures header access is consistent across middleware, endpoints, and HTTP clients.
BaseErrorCode and BaseErrorMessage operate one level deeper: they describe why a request was rejected at the field level. Each code/message pair (e.g., BaseErrorCode.EmailRequired + BaseErrorMessage.EmailRequired) populates a structured ValidationError, which the value objects in RA.Utilities.Core.ValueObjects (Email, Currency, Money, SSN, IBAN) throw and the RA.Utilities.Api middleware translates into standardized HTTP 400 responses.
HTTP Response
├─ Status Code: BaseResponseCode.NotFound (404)
├─ Body:
│ ├─ responseCode: 404
│ ├─ responseType: 8 ← ResponseType.NotFound (numeric by default)
│ └─ responseMessage: "Product with value '99' not found."
└─ Headers:
└─ x-request-id: "abc-123" ← HeaderParameters.XRequestId
ResponseType is a plain C# enum, so System.Text.Json writes its numeric value (ResponseType.NotFound → 8) unless you register JsonStringEnumConverter. See ResponseType for the exact setup.
Terminology
- Magic strings/numbers: Hard-coded literals scattered throughout code. Replacing them with named values improves readability and prevents typos.
- Static read-only field: A
public static readonlymember whose value is assigned once when the type is initialized. It behaves like a constant at call sites but is not a compile-time constant, so it cannot be used in constant-required contexts. - Semantic response type: An
enummember that labels the outcome inside the JSON body.System.Text.Jsonwrites the numeric member value by default; registerJsonStringEnumConverterif your contract expects names such as"NotFound". SeeResponseTypefor details.
📖 How-To Guides
Return a 404 with consistent messaging
using Microsoft.AspNetCore.Mvc;
using RA.Utilities.Core.Constants;
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
[HttpGet("{id}")]
public IActionResult GetProduct(int id)
{
var product = _productService.GetById(id);
if (product == null)
{
return NotFound(BaseResponseMessages.NotFound);
}
return Ok(product);
}
}
Return a 400 for invalid input
[HttpPost]
public IActionResult CreateProduct([FromBody] Product newProduct)
{
if (!ModelState.IsValid)
{
return BadRequest(BaseResponseMessages.BadRequest);
}
var createdProduct = _productService.Create(newProduct);
return CreatedAtAction(nameof(GetProduct), new { id = createdProduct.Id }, createdProduct);
}
Use consistent header names
[HttpGet("trace")]
public IActionResult GetTraceId()
{
if (Request.Headers.TryGetValue(HeaderParameters.XRequestId, out var requestId))
{
return Ok(new { requestId });
}
return BadRequest(BaseResponseMessages.BadRequest);
}
Reject invalid input with a structured validation error
using RA.Utilities.Core.Constants;
using RA.Utilities.Core.Exceptions;
if (string.IsNullOrWhiteSpace(request.Email))
{
// Pair the machine-readable code with its human-readable message
throw new BadRequestException(new ValidationError(BaseErrorMessage.EmailRequired)
{
PropertyName = "Email",
ErrorCode = BaseErrorCode.EmailRequired
});
}
See BaseErrorCode and BaseErrorMessage for the full catalog and the JSON shape these errors produce.
Validate an IBAN and pick the right error code
IBAN validation has four codes so clients can tell a missing value from a country-length mismatch, a malformed value, and a failed check digit:
| Situation | Error code | Message |
|---|---|---|
| Value is null, empty, or whitespace | BaseErrorCode.IbanRequired | BaseErrorMessage.IbanRequired |
| Structure is invalid (country code, check digits, or 13–34 characters) | BaseErrorCode.IbanNotValid | BaseErrorMessage.IbanNotValid |
| ISO 7064 mod-97 check fails | BaseErrorCode.IbanCheckDigits | BaseErrorMessage.IbanCheckDigits |
| Length does not match the country's registry entry | BaseErrorCode.IbanLength | BaseErrorMessage.IbanLength |
The IBAN value object in RA.Utilities.Core.ValueObjects applies the first three checks and throws the matching BadRequestException:
using RA.Utilities.Core.Exceptions;
using RA.Utilities.Core.ValueObjects;
IBAN iban = new(request.Iban); // REQUIRED_IBAN, NOT_VALID_IBAN, or IBAN_CHECK_DIGITS
The value object validates the IBAN structure (13–34 characters) rather than a per-country length table, so use IbanLength when you enforce the registry length yourself:
using System.Collections.Generic;
using RA.Utilities.Core.Constants;
using RA.Utilities.Core.Exceptions;
// A subset of the SWIFT IBAN registry: country code -> total length.
private static readonly Dictionary<string, int> IbanLengths = new()
{
["DE"] = 22,
["FR"] = 27,
["GB"] = 22,
["NL"] = 18
};
public static void EnsureCountryLength(string countryCode, string compactIban)
{
if (IbanLengths.TryGetValue(countryCode, out int expected) && compactIban.Length != expected)
{
throw new BadRequestException(new ValidationError(BaseErrorMessage.IbanLength)
{
PropertyName = "IBAN",
ErrorCode = BaseErrorCode.IbanLength,
AttemptedValue = compactIban.Length,
ExpectedValue = expected
});
}
}
See BaseErrorCode and BaseErrorMessage for the full catalog.
Serialize ResponseType as a string
ResponseType is an enum with no built-in converter. If your API contract exposes names ("NotFound") instead of numbers (8), register JsonStringEnumConverter for the serializer used by your endpoints:
using System.Text.Json.Serialization;
// Minimal APIs / Results.Json — this is what RA.Utilities.Api uses
builder.Services.ConfigureHttpJsonOptions(options =>
{
options.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
});
// MVC controllers — configure AddControllers().AddJsonOptions(...) the same way
Verify the behavior your clients depend on: with JsonStringEnumConverter, names are written as-is, matched case-insensitively on read, and unknown names throw JsonException. See ResponseType for details.
Handle an outcome that has no dedicated ResponseType member
The set of ResponseType values is closed. For an outcome without a dedicated member (e.g., HTTP 502 Bad Gateway), use the closest built-in member and communicate the specifics through the error code and message:
throw new RaBaseException(502, ResponseType.Error, "The upstream service failed.");
⚙️ Configuration
This package has no configuration options. There is no DI registration, no appsettings.json entries, and no options classes. All values are public static readonly fields or enum members — reference them directly.
The only optional setup is JSON serialization: if your API contract requires enum names instead of numbers, register JsonStringEnumConverter as shown in Serialize ResponseType as a string. That configures System.Text.Json, not this package.
✨ Available Constants
BaseErrorCode
The BaseErrorCode class provides a centralized, single source of truth for the machine-readable error codes returned when field-level validation fails.
BaseErrorMessage
The BaseErrorMessage class provides a collection of predefined, read-only string messages for field-level validation failures.
BaseResponseCode
The BaseResponseCode class provides a centralized, single source of truth for common HTTP status codes used throughout your application ecosystem.
BaseResponseMessages
The BaseResponseMessages class provides a collection of predefined, read-only string messages for common API responses.
HeaderParameters
The HeaderParameters class acts as a central repository for common HTTP header names used throughout your services.
ResponseType
The ResponseType is a C# enum that provides a strongly-typed, descriptive vocabulary for the outcomes of your API operations, going beyond what standard HTTP status codes can offer.
Migration Guides
v10.0.3 → v10.1.0
Troubleshooting & FAQ
Common Issues
🙌 Contributing & Support
Found a bug or have a suggestion?
- GitHub Issues: Report a bug or request a feature
- Discussions: Ask questions or start a discussion
Contributing
Contributions are welcome! Please follow the standard workflow:
- Fork the RA.Utilities repository
- Create a branch from
mainwith a descriptive name (e.g.,feature/add-new-constant) - Make your changes — ensure XML doc comments are included for any new public API
- Submit a pull request to the
mainbranch with a clear description
Links
| Resource | URL |
|---|---|
| NuGet | RA.Utilities.Core.Constants |
| Source | GitHub — RedonAlla/RA.Utilities |
| License | MIT |
| Build Status | GitHub Actions |