Package Description
License
—
Deps
0
Install Size
—
Vulns
✓ 0
Published
Feb 13, 2026
$ dotnet add package Nedo.AspNet.Request.InputValidationMiddleware-level input validation library for ASP.NET Core. Validates the format, structure, and safety of HTTP requests before model binding — catching threats that field-level validation ([Required], [Range], etc.) cannot.
Field-level validation ([Required], [EmailAddress], FluentValidation) validates property values after model binding. But it cannot protect against:
| Threat | Example |
|---|---|
| Invalid Content-Type | Sending text/xml to a JSON endpoint |
| Malformed JSON | { invalid json crashing the deserializer |
| Oversized Payloads | 100MB body on a simple form endpoint |
| Deep Nesting Attacks | Deeply nested JSON causing stack overflow |
| Invalid MIME Types | Malformed Content-Type header syntax |
Nedo.AspNet.Request.InputValidation fills this gap by validating at the HTTP pipeline level, before model binding occurs.
HTTP Request
│
▼
┌──────────────────────────────────────┐
│ 🛡️ Request Input Validation │ ◄── THIS LIBRARY
│ (Content-Type, JSON, Size, Format) │
└──────────────┬───────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ 📦 Model Binding & Deserialization │
└──────────────┬───────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ ✅ Field-Level Validation │ ◄── [Required], [Range], etc.
└──────────────┬───────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ 🎯 Controller / Endpoint Logic │
└──────────────────────────────────────┘
dotnet add package Nedo.AspNet.Request.InputValidation
using Nedo.AspNet.Request.InputValidation;
var builder = WebApplication.CreateBuilder(args);
// Option A: Using appsettings.json
builder.Services.AddRequestInputValidation(
builder.Configuration.GetSection("NedoRequestInputValidation")
);
// Option B: Using code
builder.Services.AddRequestInputValidation(options =>
{
options.EnableFormatValidators = true;
options.MaxRequestBodySize = 10_000_000; // 10MB
options.MaxJsonDepth = 32;
options.AllowedContentTypes.Add("application/json");
});
Add the middleware to the pipeline before your endpoints:
var app = builder.Build();
app.UseRequestInputValidation(); // Add before MapControllers / MapEndpoints
app.MapControllers();
app.Run();
Add the NedoRequestInputValidation section to your appsettings.json:
{
"NedoRequestInputValidation": {
"EnableFormatValidators": true,
"MaxJsonDepth": 32,
"MaxRequestBodySize": 10485760,
"AllowedContentTypes": [
"application/json",
"multipart/form-data"
],
"ExcludedPaths": [
"/hub",
"/signalr"
]
}
}
Then bind it in Program.cs:
builder.Services.AddRequestInputValidation(
builder.Configuration.GetSection("NedoRequestInputValidation")
);
Note: When using
appsettings.json, theAllowedContentTypeslist is exactly what you define — there are no hidden defaults. If you don't configure it, all content types are allowed.
builder.Services.AddRequestInputValidation(options =>
{
options.EnableFormatValidators = true;
options.MaxRequestBodySize = 5_000_000;
options.MaxJsonDepth = 10;
options.AllowedContentTypes.Add("application/json");
options.AllowedContentTypes.Add("multipart/form-data");
options.ExcludedPaths.Add("/hub");
});
| Option | Type | Default | Description |
|---|---|---|---|
EnableSecurityValidators | bool | true | Enable security validators (SQL Injection, XSS, etc.) — reserved for future phases |
EnableContentValidators | bool | true | Enable content validators (Required fields, etc.) — reserved for future phases |
EnableEncodingValidators | bool | true | Enable encoding validators (UTF-8, binary rejection) — reserved for future phases |
EnableFormatValidators | bool | true | Enable format validators (Content-Type, JSON syntax, body size) |
MaxJsonDepth | int | 32 | Maximum allowed JSON nesting depth |
MaxRequestBodySize | long | 30,000,000 | Maximum request body size in bytes (~30MB) |
AllowedContentTypes | List<string> | [] (empty) | Allowed Content-Type values. Empty = allow all |
ExcludedPaths | List<string> | [] (empty) | Request paths to skip validation (prefix match, case-insensitive) |
Order: 10 | Error Codes: INV-FMT-001, INV-FMT-002
Validates the Content-Type header of incoming requests.
ContentLength is 0 or null)AllowedContentTypes is empty (not configured)application/json; charset=utf-8 → checks application/json)Examples:
✅ POST /api/data Content-Type: application/json → Passes (if "application/json" is allowed)
✅ POST /api/data Content-Type: application/json; charset=utf-8 → Passes
❌ POST /api/data Content-Type: text/xml → INV-FMT-002 (not in allowed list)
❌ POST /api/data (no Content-Type header) → INV-FMT-001 (missing)
Order: 11 | Error Code: INV-FMT-003
Validates that the Content-Type header is a syntactically valid MIME type (RFC compliant).
MediaTypeHeaderValue.TryParse() for RFC-compliant parsingExamples:
✅ Content-Type: application/json → Passes (valid syntax)
✅ Content-Type: multipart/form-data → Passes
❌ Content-Type: invalid-format/ → INV-FMT-003 (invalid MIME syntax)
Order: 5 | Error Code: INV-FMT-004
Validates the size of the request body based on the Content-Length header. Runs early in the pipeline to reject oversized payloads before any processing.
Examples:
✅ POST /api/data Content-Length: 1024 (MaxRequestBodySize: 10MB) → Passes
❌ POST /api/data Content-Length: 50MB (MaxRequestBodySize: 10MB) → INV-FMT-004
Order: 20 | Error Codes: INV-FMT-005, INV-FMT-006
Validates that the request body contains valid JSON syntax before model binding attempts deserialization. Also enforces maximum nesting depth.
Content-Type: application/jsonExamples:
✅ {"name": "John", "age": 30} → Passes
❌ {"name": "John", "age": → INV-FMT-005 (invalid JSON)
❌ {"a":{"b":{"c":{"d":1}}}} (MaxDepth: 2) → INV-FMT-005 (depth exceeded)
| Code | Validator | Description |
|---|---|---|
INV-FMT-001 | ContentTypeValidator | Content-Type header is missing |
INV-FMT-002 | ContentTypeValidator | Content-Type is not in the allowed list |
INV-FMT-003 | MediaTypeValidator | Content-Type has invalid MIME type syntax |
INV-FMT-004 | InputStreamValidator | Request body exceeds maximum size |
INV-FMT-005 | JsonFormatValidator | Invalid JSON syntax or depth exceeded |
INV-FMT-006 | JsonFormatValidator | Unable to read request body |
When validation fails, the middleware returns 400 Bad Request with a structured JSON response:
{
"status": 400,
"title": "Input Validation Failed",
"errors": [
{
"code": "INV-FMT-002",
"message": "Content-Type 'text/xml' is not allowed.",
"field": "Header:Content-Type",
"category": "InputFormat"
}
]
}
Multiple errors can be returned in a single response if multiple validators detect issues.
Use ExcludedPaths to skip validation for specific routes. This is useful for:
/hub, /signalr) — WebSocket negotiation has different content patterns/health, /ready){
"NedoRequestInputValidation": {
"ExcludedPaths": [
"/hub",
"/signalr",
"/health"
]
}
}
Path matching is prefix-based and case-insensitive:
/hub matches /hub, /hub/negotiate, /hub/stream, etc./api/internal matches /api/internal/status, /api/internal/debug, etc.You can create your own validators by implementing IRequestInputValidator:
using Microsoft.AspNetCore.Http;
using Nedo.AspNet.Request.InputValidation.Contracts;
public class CustomHeaderValidator : IRequestInputValidator
{
public int Order => 15; // Controls execution order (lower = first)
public Task<InputValidationResult> ValidateAsync(HttpContext context)
{
if (!context.Request.Headers.ContainsKey("X-Api-Key"))
{
return Task.FromResult(InputValidationResult.Failure(new InputValidationError
{
Code = "INV-CUS-001",
Message = "X-Api-Key header is required.",
Field = "Header:X-Api-Key",
Category = "Custom"
}));
}
return Task.FromResult(InputValidationResult.Success);
}
}
Register it in DI:
builder.Services.AddSingleton<IRequestInputValidator, CustomHeaderValidator>();
| Aspect | Field-Level Validation | Request Input Validation (This Library) |
|---|---|---|
| Level | Property level | HTTP Request / Pipeline level |
| When | After model binding | Before model binding |
| What | Property values (string, int, DateTime) | Raw request (headers, body stream) |
| Focus | Correctness (format, range, pattern) | Safety (format, size, structure) |
| Integration | Attributes, FluentValidation | Middleware |
| Error Codes | VAL-xxx-xxx | INV-xxx-xxx |
Use both together for a complete validation pipeline:
Request → [Input Validation] → [Model Binding] → [Field Validation] → Controller
🛡️ Safety 📦 Parse ✅ Correctness 🎯 Logic
MIT