.NET Core 2.0如何为自定义Accept头配置内置XML/JSON格式化器
Great question! To let clients request HATEOAS links using custom Accept headers like application/json+hateoas or application/xml+hateoas, we need to extend the default formatters and add conditional logic in controllers. Here's a step-by-step implementation:
Step 1: Configure Custom Media Types in ConfigureServices
First, we'll register the custom media types with the existing JSON and XML formatters so the API recognizes them. Update your AddMvc configuration like this:
public void ConfigureServices(IServiceCollection services) { services.AddMvc(options => { // Map custom formats to their respective media types options.FormatterMappings.SetMediaTypeMappingForFormat( "json+hateoas", MediaTypeHeaderValue.Parse("application/json+hateoas")); options.FormatterMappings.SetMediaTypeMappingForFormat( "xml+hateoas", MediaTypeHeaderValue.Parse("application/xml+hateoas")); // Add custom media type to the default JSON formatter var jsonFormatter = options.OutputFormatters.OfType<JsonOutputFormatter>().First(); jsonFormatter.SupportedMediaTypes.Add( MediaTypeHeaderValue.Parse("application/json+hateoas")); // Add custom media type to the default XML formatter var xmlFormatter = options.OutputFormatters.OfType<XmlDataContractSerializerOutputFormatter>().First(); xmlFormatter.SupportedMediaTypes.Add( MediaTypeHeaderValue.Parse("application/xml+hateoas")); }); }
Step 2: Add Conditional HATEOAS Logic in Controllers
Create a helper method to check if the client requested HATEOAS, then modify your response to include links when needed:
private bool ShouldIncludeHateoas(HttpRequest request) { var acceptHeader = request.Headers["Accept"].ToString(); return acceptHeader.Contains("application/json+hateoas") || acceptHeader.Contains("application/xml+hateoas"); } [HttpGet("{id}")] public IActionResult Get(int id) { // Fetch your resource (example: a User object) var user = _userService.GetById(id); if (ShouldIncludeHateoas(Request)) { // Add HATEOAS navigation links user.Links = new List<Link> { new Link { Rel = "self", Href = Url.Action("Get", new { id = user.Id }), Method = "GET" }, new Link { Rel = "delete", Href = Url.Action("Delete", new { id = user.Id }), Method = "DELETE" } }; } return Ok(user); }
Step 3: Define a Link Class
Make sure you have a simple Link class to represent navigation links, and update your resource class to include a nullable Links property:
public class Link { public string Rel { get; set; } // Relationship name (e.g., "self", "update") public string Href { get; set; } // URL to the related resource public string Method { get; set; } // HTTP method for the link } // Example resource class with optional Links property public class User { public int Id { get; set; } public string Username { get; set; } public string Email { get; set; } public List<Link> Links { get; set; } // Will be null if HATEOAS isn't requested }
Key Notes
- The custom media types reuse the default formatters, so serialization/deserialization works exactly like standard JSON/XML—only the links are added conditionally.
- For XML serialization, add
[DataContract]and[DataMember]attributes to yourLinkand resource classes if you haven't already, to ensure proper XML output. - The
Linksproperty will be omitted from responses when HATEOAS isn't requested (since it's null), keeping your standard responses clean.
内容的提问来源于stack exchange,提问作者Daniel

