Custom IOutputFormatter for .NET 10 Web API that automatically serializes IEnumerable<T> to CSV when Accept: text/csv header is present.
- 🔄 Auto-detection — CSV on
Accept: text/csv, JSON otherwise - 📦 Streaming — Low memory footprint for large datasets
- 🔤 Proper escaping — Handles commas, quotes, newlines correctly
- 📅 Smart formatting — ISO 8601 dates, lowercase booleans
- 🔧 Easy setup — One-line registration via extension method
- 🎯 Type-safe — Works with any
IEnumerable<T>
using CsvOutputFormatter.Extensions;
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddControllers()
.AddCsvOutputFormatter();
var app = builder.Build();
app.MapControllers();
app.Run();[ApiController]
[Route("api/[controller]")]
public class TradesController : ControllerBase
{
[HttpGet]
public IEnumerable<Trade> GetTrades() => _service.GetAll();
}
public record Trade(int Id, string Symbol, decimal Price, DateTime Timestamp, string Side);| Request | Response |
|---|---|
GET /api/tradesAccept: application/json |
[{"id":1,"symbol":"AAPL","price":178.52}] |
GET /api/tradesAccept: text/csv |
csv\nId,Symbol,Price,Timestamp,Side\n1,AAPL,178.52,2024-01-15T10:30:00,Buy |
builder.Services.AddControllers(options =>
{
options.OutputFormatters.Insert(0, new CsvOutputFormatter());
});builder.Services
.AddControllers()
.AddCsvOutputFormatter(options =>
{
// Configure MvcOptions here if needed
});| Type | Format |
|---|---|
string, int, decimal, etc. |
Default ToString() |
DateTime |
ISO 8601: yyyy-MM-ddTHH:mm:ss |
bool |
true / false |
null |
Empty string |
Values containing ,, ", \n, or \r are automatically:
- Wrapped in double quotes
- Internal quotes escaped as
""
Example: value "with" commas → "value ""with"" commas"
CsvOutputFormatter/
├── Formatters/
│ └── CsvOutputFormatter.cs # Core formatter implementation
├── Extensions/
│ └── ServiceCollectionExtensions.cs # Registration helpers
├── assets/
│ └── banner.svg # Project banner
├── README.md # English docs (this file)
├── README-RU.md # Russian docs
└── CsvOutputFormatter.csproj # NuGet package config
- Works with
IEnumerable<T>of complex types only - Serializes public parameterless properties only
- Nested objects rendered via
ToString() - For complex formatting, use dedicated DTOs
- Fork the repository
- Create your feature branch:
git checkout -b feature/AmazingFeature - Commit changes:
git commit -m 'Add AmazingFeature' - Push:
git push origin feature/AmazingFeature - Open a Pull Request
Distributed under the MIT License. See LICENSE for more information.
Built with ❤️ for .NET developers
↑ Back to top ↑