Content type negotiation, custom formatters, Accept headers, and response format configuration. Trigger: content negotiation, Accept header, formatter, content type, media type.
From dotnet-ai-kitnpx claudepluginhub faysilalshareef/dotnet-ai-kit --plugin dotnet-ai-kitThis skill uses the workspace's default tool permissions.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
Accept header to determine response formatapplication/json when no preference is specifiedapplication/problem+json for error responses (RFC 9457)// Program.cs — global JSON options
builder.Services.ConfigureHttpJsonOptions(options =>
{
options.SerializerOptions.Converters.Add(
new JsonStringEnumConverter());
options.SerializerOptions.DefaultIgnoreCondition =
JsonIgnoreCondition.WhenWritingNull;
options.SerializerOptions.PropertyNamingPolicy =
JsonNamingPolicy.CamelCase;
});
// Controller-specific
builder.Services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.Converters.Add(
new JsonStringEnumConverter());
options.JsonSerializerOptions.DefaultIgnoreCondition =
JsonIgnoreCondition.WhenWritingNull;
});
builder.Services.AddControllers()
.AddXmlDataContractSerializerFormatters();
// Endpoints now respond to:
// Accept: application/json → JSON
// Accept: application/xml → XML
public sealed class CsvOutputFormatter : TextOutputFormatter
{
public CsvOutputFormatter()
{
SupportedMediaTypes.Add(
MediaTypeHeaderValue.Parse("text/csv"));
SupportedEncodings.Add(Encoding.UTF8);
}
protected override bool CanWriteType(Type? type)
{
return type is not null &&
(typeof(IEnumerable).IsAssignableFrom(type) ||
type.IsGenericType);
}
public override async Task WriteResponseBodyAsync(
OutputFormatterWriteContext context,
Encoding selectedEncoding)
{
var response = context.HttpContext.Response;
var items = (IEnumerable<object>)context.Object!;
var sb = new StringBuilder();
var properties = context.ObjectType!
.GetGenericArguments()[0]
.GetProperties();
// Header row
sb.AppendLine(string.Join(",",
properties.Select(p => p.Name)));
// Data rows
foreach (var item in items)
{
var values = properties.Select(p =>
EscapeCsvValue(p.GetValue(item)?.ToString() ?? ""));
sb.AppendLine(string.Join(",", values));
}
await response.WriteAsync(sb.ToString(), selectedEncoding);
}
private static string EscapeCsvValue(string value)
{
if (value.Contains(',') || value.Contains('"') ||
value.Contains('\n'))
return $"\"{value.Replace("\"", "\"\"")}\"";
return value;
}
}
// Registration
builder.Services.AddControllers(options =>
{
options.OutputFormatters.Add(new CsvOutputFormatter());
});
// Allow ?format=csv or /orders.csv
builder.Services.AddControllers(options =>
{
options.FormatterMappings.SetMediaTypeMappingForFormat(
"csv", "text/csv");
options.FormatterMappings.SetMediaTypeMappingForFormat(
"xml", "application/xml");
});
[HttpGet]
[FormatFilter]
[Route("/orders.{format?}")]
public async Task<ActionResult<List<OrderResponse>>> GetOrders() { }
// Minimal API — explicit content type
app.MapGet("/orders/{id}", async (Guid id, ISender sender) =>
{
var order = await sender.Send(new GetOrderQuery(id));
return order is not null
? Results.Ok(order)
: Results.NotFound();
}).Produces<OrderResponse>(StatusCodes.Status200OK, "application/json");
// Return specific content type
app.MapGet("/orders/export", async (ISender sender) =>
{
var csv = await sender.Send(new ExportOrdersCsvQuery());
return Results.Text(csv, "text/csv", Encoding.UTF8);
});
// Return file
app.MapGet("/orders/{id}/invoice", async (Guid id, ISender sender) =>
{
var pdf = await sender.Send(new GenerateInvoiceQuery(id));
return Results.File(
pdf, "application/pdf", $"invoice-{id}.pdf");
});
builder.Services.AddProblemDetails();
// Automatic problem+json responses for errors
app.UseExceptionHandler();
app.UseStatusCodePages();
// Custom problem details
app.MapGet("/orders/{id}", async (Guid id) =>
{
return Results.Problem(
title: "Order Not Found",
detail: $"No order exists with ID {id}",
statusCode: StatusCodes.Status404NotFound,
type: "https://tools.ietf.org/html/rfc9110#section-15.5.5");
});
Client sends:
Accept: application/json → JSON response
Accept: application/xml → XML response
Accept: text/csv → CSV response
Accept: */* → Default (JSON)
Accept: application/problem+json → Error responses
Server responds with:
Content-Type: application/json; charset=utf-8
application/problem+json for errorsAddJsonOptions or ConfigureHttpJsonOptions configurationOutputFormatter implementationsAddXmlDataContractSerializerFormatters calls[Produces] and [Consumes] attributes on controllersAddProblemDetails in Program.cs[Produces] attributes to document supported content types| Content Type | Use Case |
|---|---|
application/json | Default for API responses |
application/problem+json | Error responses (RFC 9457) |
text/csv | Data export |
application/xml | Legacy integrations |
application/pdf | Report generation |
application/octet-stream | File downloads |