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.
Join the conversation! Your thoughts help the community grow.