ASP.NET Core / Editorial solution guide

Diagnose 404,405, and Binding/Validation Failures

Trace selection, HTTP method, input source, framework validation, and action behavior before adding broad fallback routes.

About 3 min readContent reviewed

Read-only knowledge base · No public comments

Recognize the symptoms

A request gets 404 even though an action exists,405 for a familiar path, or 400/415 before a handler breakpoint is reached. A direct controller call may succeed while the public request fails. These outcomes can come from distinct routing, method, content-type, binding, or automatic validation stages; one successful unit test does not identify which stage the client actually reached.

Understand the likely causes

  • The mapping may be missing, route constraints or parameter names may differ, the HTTP method may be wrong, or binding may read a different source than expected. MVC ApiController and Minimal API validation depend on their setup. A catch-all endpoint can hide the mismatch instead of repairing it, while an internal action is not automatically a discovered public controller.

1. Preserve the exact method, path, and input representation

Record the synthetic request’s method, encoded path, query keys, content type, body shape, and expected endpoint. Compare them with the actual mapping and any route group/prefix. Avoid changing several layers at once. Distinguish a route identifier’s syntax from whether the requested entity exists or the caller may access it.

2. Separate path structure from method and constraint selection

A template match alone does not establish a full routing decision. HTTP method metadata, constraints, precedence, and the endpoint set still matter. The complete program uses TemplateMatcher with one synthetic path and compares a method separately. It is a component diagnosis, not a hosted 405 or binding test, and it sends no request traffic.

csharp Inspect path structure and a separate method rule
using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing.Template;

var matcher = new TemplateMatcher(TemplateParser.Parse("reports/{id}"), new RouteValueDictionary());
var values = new RouteValueDictionary();
bool pathMatch = matcher.TryMatch(new PathString("/reports/7"), values);
string method = HttpMethods.Post;
bool methodAllowed = HttpMethods.IsGet(method);
Console.WriteLine($"pathMatch={pathMatch} id={values["id"]} methodAllowed={methodAllowed}");
Expected output
pathMatch=True id=7 methodAllowed=False

The path structure matches 7, but the synthetic POST does not satisfy this GET rule; no router or HTTP response executes.

3. Review the declared binding source and representation

Compare route/query/header/body/service sources with the signature and explicit attributes. Missing, malformed, unsupported content type, and successfully parsed but out-of-domain values are different. A GET body is not implicitly inferred like every POST body. Do not fix a source mismatch by accepting arbitrary input from every place; define one public contract.

4. Identify whether framework validation runs before the action

ApiController may reject invalid ModelState before a controller action; Minimal APIs have their own versioned validation setup and filters. Calling the action directly bypasses those paths. Inspect safe error details and configured behavior, and separate DTO shape validation from domain ownership, current uniqueness, or workflow rules. Do not expose raw exception bodies while diagnosing.

5. Repair and test the intended endpoint surface

Fix the specific registration, route, method, source, or validation rule under review. Test valid, wrong-method, unmapped, malformed, absent-entity, unauthorized, and forbidden cases. Keep result metadata and generated links aligned. A broad fallback returning 200 can make a symptom disappear while breaking the public status contract and observability.

Verify the fix

The local program must print pathMatch=True id=7 methodAllowed=False. Verify the repaired public method/path/status contract through an approved isolated framework integration test when available. Include actual binding, automatic validation, auth, and result execution for claims about those layers. A direct template or action test remains useful narrow evidence rather than proof of an entire API.

Keep it from recurring

  • Keep a route/method/input/status table, explicit binding where ambiguity matters, and separate unit/component/integration tests. Review route and parameter-name changes as compatibility changes. Preserve synthetic counterexamples and avoid masking broken mappings with catch-alls or weakening validation.

Official references