Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> C#

Content Negotiation trong ASP.NET WebAPI C# là gì?

Content negotiation là quá trình chọn best representation cho response khi có multiple representations available. Tức là, tùy thuộc vào giá trị Accept header trong request, server gửi response. Các request headers chính cho content negotiation:

  • Accept - Media types acceptable cho response: "application/json", "application/xml", "application/vnd.example+xml"
  • Accept-Charset - Character sets acceptable: UTF-8, ISO 8859-1
  • Accept-Encoding - Content encodings acceptable: gzip, deflate
  • Accept-Language - Natural language ưu tiên: "en-us", "vi-VN"

Server cũng có thể xem các phần khác của HTTP request. Ví dụ, nếu request có header X-Requested-With chỉ ra AJAX request, server có thể default JSON nếu không có Accept header.

Trong content negotiation, pipeline lấy service IContentNegotiator từ HttpConfiguration object. Cũng lấy list media formatters từ HttpConfiguration.Formatters collection.

Pipeline gọi IContentNegotiator.Negotiate, truyền vào:

  • Type của object cần serialize
  • Collection của media formatters
  • HTTP request

Negotiate method trả về:

  • Formatter nào dùng
  • Media type cho response

Nếu không tìm thấy formatter, Negotiate trả null, client nhận HTTP 406 (Not Acceptable).

Ví dụ StudentController

using DemoWebApplication.Models; 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web.Http; 

namespace DemoWebApplication.Controllers { 
    public class StudentController : ApiController { 
        List<Student> students = new List<Student> { 
            new Student { Id = 1, Name = "Mark" }, 
            new Student { Id = 2, Name = "John" } 
        }; 
    } 
}

Một tiêu chuẩn RESTful service: client quyết định format response - XML, JSON, v.v. Request gửi đến server bao gồm Accept header. Dùng Accept header client chỉ định format response.

Accept: application/xml  → trả về XML
Accept: application/json → trả về JSON

Quality Factors (q-values)

Có thể chỉ định quality factor. Ví dụ dưới, xml có q=0.8 cao hơn json q=0.5, nên server dùng XML formatter.

Accept: application/xml;q=0.8, application/json;q=0.5

Default Behavior

  • Không có Accept header → Default formatter (thường JSON first)
  • Browser gửi Accept: text/html → Web API default trả XML (trừ khi config JSON cho text/html)
  • */ * → Chấp nhận bất kỳ format nào

Cấu hình Formatters

Chỉ giữ JSON (bỏ XML)

public static class WebApiConfig {
    public static void Register(HttpConfiguration config) {
        config.Formatters.Remove(config.Formatters.XmlFormatter);
        // Hoặc clear all và add JSON
        config.Formatters.Clear();
        config.Formatters.Add(new JsonMediaTypeFormatter());
    }
}

Thêm custom formatter (ví dụ CSV)

public class CsvMediaTypeFormatter : BufferedMediaTypeFormatter {
    public CsvMediaTypeFormatter() {
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/csv"));
    }
    public override bool CanWriteType(Type type) => true;
    public override void WriteToStream(Type type, object value, Stream writeStream, HttpContent content) {
        // Serialize to CSV
    }
}

// Register
config.Formatters.Add(new CsvMediaTypeFormatter());

Force JSON cho browser (text/html)

config.Formatters.JsonFormatter.SupportedMediaTypes
    .Add(new MediaTypeHeaderValue("text/html"));

Content Negotiation Flow

Client Request
     │
     ▼
Accept Header: application/json, application/xml;q=0.9
     │
     ▼
Server: IContentNegotiator.Negotiate(type, formatters, request)
     │
     ▼
Match: JsonMediaTypeFormatter (q=1.0) vs XmlMediaTypeFormatter (q=0.9)
     │
     ▼
Select: JsonMediaTypeFormatter
     │
     ▼
Response: Content-Type: application/json + JSON body

ASP.NET Core Content Negotiation

// Controller tự động negotiate dựa trên Accept header
[HttpGet]
public IActionResult Get() {
    var data = new { Message = "Hello", Time = DateTime.Now };
    return Ok(data); // Tự negotiate
}

// Force format
[HttpGet("json")]
public IActionResult GetJson() => Ok(data); // Luôn JSON

[HttpGet("xml")]
public IActionResult GetXml() => new XmlResult(data); // Custom result

// Cấu hình formatters
services.AddControllers(options => {
    options.RespectBrowserAcceptHeader = true; // Default false
}).AddXmlSerializerFormatters(); // Thêm XML support