Introduction
When you build APIs using ASP.NET Core Web API, your main job is not just to send data but to send it in the right format. Most APIs return JSON by default, which works for most modern applications. However, in real-world projects, you may need to return data in different formats like CSV, plain text, or even a custom format required by another system.
This is where Output Formatters become useful. They allow you to control exactly how your API response is created and sent back to the client.
In this article, we will understand Output Formatters in simple words and then implement a custom Output Formatter step by step with a clear example.
What is an Output Formatter in ASP.NET Core?
An Output Formatter is a component in ASP.NET Core Web API that converts your C# object into a specific response format before sending it to the client.
For example, when your API returns a list of products, the Output Formatter decides whether that data should be returned as JSON, XML, or any other format.
ASP.NET Core already includes built-in formatters like:
JSON Formatter (default)
XML Formatter (optional)
But if your requirement is different, you can create your own custom formatter.
Why Use a Custom Output Formatter?
In many real-world applications, default JSON output is not always enough. You might need a different format based on business requirements.
Here are some common scenarios:
You want to export data in CSV format for reports
A third-party system only accepts a specific format
You want to reduce response size using a lightweight format
You need full control over how the response is structured
In such cases, creating a custom Output Formatter becomes very useful.
Step 1: Create a Custom Output Formatter Class
To create a custom Output Formatter, you need to create a class and inherit from TextOutputFormatter.
TextOutputFormatter is used when your output is text-based, like CSV or plain text.
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Net.Http.Headers;
using System.Text;
public class CsvOutputFormatter : TextOutputFormatter
{
public CsvOutputFormatter()
{
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/csv"));
SupportedEncodings.Add(Encoding.UTF8);
SupportedEncodings.Add(Encoding.Unicode);
}
protected override bool CanWriteType(Type type)
{
if (typeof(IEnumerable<object>).IsAssignableFrom(type))
return true;
return false;
}
public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
{
var response = context.HttpContext.Response;
var buffer = new StringBuilder();
var data = context.Object as IEnumerable<object>;
if (data != null)
{
foreach (var item in data)
{
var properties = item.GetType().GetProperties();
var values = properties.Select(p => p.GetValue(item));
buffer.AppendLine(string.Join(",", values));
}
}
await response.WriteAsync(buffer.ToString());
}
}
In this step, we are doing three important things:
Defining the supported media type (text/csv)
Defining supported encodings like UTF-8
Writing logic to convert object data into CSV format
The WriteResponseBodyAsync method is the most important part because it controls how your response is generated.
Step 2: Register the Output Formatter
After creating the formatter, the next step is to register it in the ASP.NET Core pipeline.
This is done inside Program.cs.
builder.Services.AddControllers(options =>
{
options.OutputFormatters.Add(new CsvOutputFormatter());
});
This step is very important. If you don’t register your formatter, ASP.NET Core will never use it.
Once registered, ASP.NET Core will consider your formatter when deciding how to send the response.
Step 3: Create a Sample Model
Now let’s create a simple model class. This will be the data we return from the API.
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
This model represents a product with three properties: Id, Name, and Price.
Step 4: Create a Controller
Now we create a controller that returns a list of products.
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
var products = new List<Product>
{
new Product { Id = 1, Name = "Laptop", Price = 50000 },
new Product { Id = 2, Name = "Mouse", Price = 500 }
};
return Ok(products);
}
}
Here, we are simply returning a list of products using Ok().
ASP.NET Core will now decide which formatter to use when sending this response.
Step 5: Test Using Accept Header
To use your custom Output Formatter, the client must request the correct format using the Accept header.
Example:
Accept: text/csv
You can test this using tools like Postman or Swagger.
When this header is present, ASP.NET Core will select your CsvOutputFormatter instead of the default JSON formatter.
Expected Output
When everything works correctly, the response will look like this:
1,Laptop,50000
2,Mouse,500
This is a simple CSV format where each row represents one product.
How Content Negotiation Works
Content Negotiation is the process where ASP.NET Core decides which formatter to use.
It works based on:
The Accept header sent by the client
The list of supported media types
The order in which formatters are registered
If no matching formatter is found, ASP.NET Core will return JSON by default.
Best Practices for Output Formatter
When working with custom Output Formatters, follow these best practices:
Keep your logic simple and easy to maintain
Always check for null values to avoid runtime errors
Avoid heavy reflection if performance is important
Support common encodings like UTF-8
Write clean and readable code
When to Use TextOutputFormatter vs OutputFormatter
Choosing the right base class is important:
Use TextOutputFormatter when working with text formats like CSV, HTML, or plain text
Use OutputFormatter when working with binary data like files or streams
Common Mistakes to Avoid
Many developers face issues while implementing Output Formatters. Here are some common mistakes:
Forgetting to register the formatter
Using incorrect media type
Not handling different data types properly
Writing complex and slow formatting logic
Avoiding these mistakes will save debugging time.
Real-World Use Cases
Custom Output Formatters are widely used in real applications:
Exporting reports in CSV format
Providing data to legacy systems
Creating lightweight APIs for performance optimization
Supporting multiple client requirements
Summary
Output Formatters in ASP.NET Core Web API help you control how your API response is sent to the client. By creating a custom Output Formatter, you can return data in formats like CSV or any structure required by your application. The process involves creating a formatter class, registering it, and testing it using the Accept header. With proper implementation and best practices, Output Formatters make your API more flexible, powerful, and production-ready.