ASP.NET Core API returns HTML instead of JSON
Complete Fix Guide
“Your API returns HTML when you expected JSON” — This is a common but frustrating issue when building REST APIs with ASP.NET Core. This guide explains why it happens and provides concrete, production-ready solutions for every scenario.
📑 Table of Contents
1. Introduction
You’re building a clean REST API with ASP.NET Core. You test it in Postman or your Angular app,
and instead of receiving JSON, you get a full HTML page. The response Content-Type
is text/html instead of application/json. This can be confusing and
break your client-side application.
This issue usually stems from how ASP.NET Core handles content negotiation, exception handling, or misconfigured formatters. The good news: it’s almost always a straightforward fix. This guide walks you through every possible cause and solution.
Accept header. If the client doesn't send application/json
or the server can't serialize the response, it may fall back to HTML.
2. Common Causes
- Missing or incorrect
Acceptheader – The client doesn't request JSON. - Unhandled exceptions – The Developer Exception Page returns HTML (in development).
- Invalid model state –
[ApiController]returns a validation error page. - Wrong return type – Returning an object that can't be serialized to JSON.
- XML formatter – The client requests XML, and the server returns it.
- Misconfigured
JsonSerializerSettings– Circular references or recursion. - Custom middleware – Middleware intercepts and returns HTML.
3. Accept Header
The Accept header tells the server what content types the client can handle.
If your client sends Accept: text/html or omits the header, ASP.NET Core may return
HTML (if the XML/JSON formatters can't handle the response).
✅ Correct Client Request (Angular / HttpClient)
✅ Postman / cURL
🔧 Force JSON Response on the Server
If you want the API to always return JSON regardless of the Accept header, you can configure the server to ignore Accept and use JSON as the default.
4. Exception Handling
When an unhandled exception occurs in development, ASP.NET Core returns the Developer Exception Page (HTML) by default. In production, it returns a static error page or the configured exception handler. This is a common source of HTML responses in APIs.
✅ Global Exception Middleware to Return JSON
✅ Using ProblemDetails (RFC 7807)
ProblemDetails for standards compliance.
5. JSON Formatters
ASP.NET Core supports multiple output formatters (JSON, XML, etc.). If the client's Accept header matches XML first, the API may return XML. Here's how to control formatters.
✅ Remove XML Formatter
If you want to only support JSON, remove the XML formatter:
✅ Use AddNewtonsoftJson (if needed)
If you have legacy code that depends on Newtonsoft.Json, you can use it instead of System.Text.Json:
6. Return Types
If your action method returns an object that cannot be serialized to JSON (e.g., Stream,
FileStream, or a type with circular references), ASP.NET Core may fall back to HTML.
✅ Use IActionResult with Ok()
✅ Use ActionResult<T>
✅ Handle Circular References
7. Invalid Model State
When using [ApiController], ASP.NET Core automatically validates model state and
returns a 400 Bad Request with validation errors. If the client doesn't accept JSON,
it may return HTML.
This custom factory ensures that validation errors always return JSON.
8. Debugging
- Check the request Accept header: In DevTools or Postman, inspect the request headers.
- Inspect the response Content-Type: It should be
application/json. - Enable logging: Add
builder.Logging.AddConsole()to see what's happening. - Use the
Producesattribute: Add[Produces("application/json")]to your controller or action. - Check for middleware order: Middleware order matters.
UseExceptionHandlerandUseRoutingshould be correctly placed. - Test with cURL:
curl -H "Accept: application/json" https://localhost:5001/api/testto isolate client issues. - Use
return Json(...): For older or custom code, you can usereturn Json(new { property = "value" }).
10. Best Practices
- Always set the
Acceptheader – Clients should explicitly requestapplication/json. - Use
[Produces("application/json")]to force JSON responses on your controllers. - Implement global exception handling that returns structured JSON errors.
- Use
ProblemDetailsfor standardized error responses (RFC 7807). - Remove XML formatters if your API only serves JSON.
- Configure JSON options globally for consistent serialization (camelCase, reference handling).
- Use
ActionResult<T>for strongly typed responses. - Log all unhandled exceptions for monitoring and debugging.
- Test your API with different Accept headers to ensure it behaves correctly.

0 Comments
thanks for your comments!