Section 5 of 6

Headers and Content Types

🎯 What You'll Learn

  • Common HTTP headers
  • Content-Type and Accept headers
  • Content negotiation
  • Custom headers
  • CORS headers
  • How to read and set headers in ASP.NET Core
  • Complete InvenTrack examples

What are HTTP Headers?

HTTP headers are key-value pairs that provide metadata about the request or response.

Example Headers HTTP
GET /api/products HTTP/1.1
Host: inventrackapp.com
User-Agent: Mozilla/5.0
Accept: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

Common Request Headers

Header Purpose Example
Host Target server inventrackapp.com
User-Agent Client information Mozilla/5.0
Accept Expected response format application/json
Content-Type Format of request body application/json
Authorization Authentication credentials Bearer token...
Cookie Cookies sent to server sessionId=abc123

Common Response Headers

Header Purpose Example
Content-Type Format of response body application/json
Content-Length Size of response body 1234
Location URL of created resource /api/products/123
Set-Cookie Set cookie in browser sessionId=abc123
Cache-Control Caching directives no-cache
Access-Control-Allow-Origin CORS policy *

Content-Type Header

Content-Type specifies the format of the request/response body.

Common Content Types

Content-Type Description Use Case
application/json JSON data APIs (most common)
application/xml XML data Legacy APIs, SOAP
text/html HTML document Web pages
text/plain Plain text Simple text responses
multipart/form-data Form with files File uploads
application/x-www-form-urlencoded Form data HTML forms
JSON Request HTTP
POST /api/products HTTP/1.1
Content-Type: application/json

{
  "name": "Laptop",
  "price": 999.99
}

Content Negotiation

Content negotiation allows clients to request different response formats using the Accept header.

Request JSON HTTP
GET /api/products/123 HTTP/1.1
Accept: application/json
Request XML HTTP
GET /api/products/123 HTTP/1.1
Accept: application/xml

Enable Content Negotiation in ASP.NET Core

Program.cs C#
builder.Services.AddControllers(options =>
{
    options.RespectBrowserAcceptHeader = true; // Enable content negotiation
})
.AddXmlSerializerFormatters(); // Add XML support

Reading Headers in ASP.NET Core

Read Request Headers C#
[HttpGet]
public IActionResult GetProducts()
{
    // Read specific header
    var userAgent = Request.Headers["User-Agent"].ToString();
    
    // Read Authorization header
    var authHeader = Request.Headers["Authorization"].ToString();
    
    // Check if header exists
    if (Request.Headers.ContainsKey("X-API-Key"))
    {
        var apiKey = Request.Headers["X-API-Key"].ToString();
    }
    
    // Read Content-Type
    var contentType = Request.ContentType;
    
    return Ok();
}

Using [FromHeader] Attribute

Bind Header to Parameter C#
[HttpGet]
public IActionResult GetProducts(
    [FromHeader(Name = "X-API-Key")] string apiKey,
    [FromHeader(Name = "X-Request-Id")] string? requestId = null)
{
    // apiKey and requestId are automatically bound from headers
    return Ok();
}

Setting Response Headers

Set Response Headers C#
[HttpGet]
public IActionResult GetProducts()
{
    // Set custom headers
    Response.Headers["X-Total-Count"] = "100";
    Response.Headers["X-API-Version"] = "1.0";
    Response.Headers["X-Response-Time"] = "45ms";
    
    // Set Cache-Control
    Response.Headers["Cache-Control"] = "no-cache";
    
    return Ok(new List<Product>());
}

Custom Headers

Custom headers should start with X- (convention).

Common Custom Headers

  • X-API-Key: API authentication
  • X-Request-Id: Request tracking
  • X-Correlation-Id: Distributed tracing
  • X-Total-Count: Total items in paginated response
  • X-Response-Time: Server processing time
InvenTrack Custom Headers C#
[HttpGet]
public async Task<IActionResult> GetProducts(
    [FromQuery] int page = 1,
    [FromQuery] int pageSize = 10)
{
    var result = await _productService.GetPagedAsync(page, pageSize);
    
    // Add pagination headers
    Response.Headers["X-Total-Count"] = result.TotalCount.ToString();
    Response.Headers["X-Page"] = page.ToString();
    Response.Headers["X-Page-Size"] = pageSize.ToString();
    Response.Headers["X-Total-Pages"] = result.TotalPages.ToString();
    
    return Ok(result.Items);
}

CORS Headers

CORS (Cross-Origin Resource Sharing) headers allow browsers to make cross-origin requests.

Common CORS Headers

  • Access-Control-Allow-Origin: Allowed origins
  • Access-Control-Allow-Methods: Allowed HTTP methods
  • Access-Control-Allow-Headers: Allowed headers
  • Access-Control-Allow-Credentials: Allow cookies
Program.cs - CORS Configuration C#
builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowFrontend", policy =>
    {
        policy.WithOrigins("https://inventrackapp.com")
              .AllowAnyMethod()
              .AllowAnyHeader()
              .AllowCredentials();
    });
});

var app = builder.Build();

app.UseCors("AllowFrontend");

Complete InvenTrack Example

Controllers/ProductsController.cs C#
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    private readonly IProductService _productService;

    public ProductsController(IProductService productService)
    {
        _productService = productService;
    }

    // Pagination with custom headers
    [HttpGet]
    public async Task<IActionResult> GetProducts(
        [FromQuery] int page = 1,
        [FromQuery] int pageSize = 10)
    {
        var result = await _productService.GetPagedAsync(page, pageSize);
        
        // Add pagination headers
        Response.Headers["X-Total-Count"] = result.TotalCount.ToString();
        Response.Headers["X-Page"] = page.ToString();
        Response.Headers["X-Page-Size"] = pageSize.ToString();
        Response.Headers["X-Total-Pages"] = result.TotalPages.ToString();
        
        return Ok(result.Items);
    }

    // API Key from header
    [HttpGet("secure")]
    public IActionResult GetSecureData(
        [FromHeader(Name = "X-API-Key")] string apiKey)
    {
        if (apiKey != "secret-key-123")
            return Unauthorized();
        
        return Ok("Secure data");
    }

    // Content negotiation (JSON/XML)
    [HttpGet("{id}")]
    [Produces("application/json", "application/xml")]
    public async Task<IActionResult> GetProduct(int id)
    {
        var product = await _productService.GetByIdAsync(id);
        
        if (product == null)
            return NotFound();
        
        // Returns JSON or XML based on Accept header
        return Ok(product);
    }

    // File upload (multipart/form-data)
    [HttpPost("upload")]
    public async Task<IActionResult> UploadImage(IFormFile file)
    {
        if (file == null || file.Length == 0)
            return BadRequest("No file uploaded");
        
        // Check Content-Type
        if (!file.ContentType.StartsWith("image/"))
            return BadRequest("Only images allowed");
        
        var url = await _productService.UploadImageAsync(file);
        
        return Ok(new { imageUrl = url });
    }
}

Key Takeaways

  • Headers: Key-value pairs with request/response metadata
  • Content-Type: Format of request/response body
  • Accept: Client's preferred response format
  • Content negotiation: Return different formats (JSON/XML)
  • Custom headers: Start with X- (e.g., X-API-Key)
  • CORS headers: Enable cross-origin requests
  • Read headers with Request.Headers
  • Set headers with Response.Headers
  • Use [FromHeader] to bind headers to parameters
  • Use [Produces] for content negotiation
🎯 Next Steps

You now understand HTTP headers and content types! In the final section, we'll explore Cookies and Sessions—how to maintain state across requests, session management, and cookie security.