如何在 C# ASP.NET WebAPI 中使用自定義媒體型別進行版本控制?
媒體型別允許 API 讓客戶端了解如何解釋有效負載中的資料。在 HTTP 協議中,媒體型別使用 text/html、application/json 和 application/xml 等識別符號指定,媒體型別分別對應最常見的 Web 格式 HTML、JSON 和 XML。還有其他更基於 API 的媒體型別,例如 application/vnd.api+json。
以下是需要在媒體型別中傳送的版本。
application/vnd.demo.students.v1+json StudentsV1Controller application/vnd.demo.students.v2+json StudentsV2Controller
新增我們自己的 CustomControllerSelector 將修復上述錯誤。
CustomControllerSelector −
示例
using System.Linq; using System.Net.Http; using System.Text.RegularExpressions; using System.Web.Http; using System.Web.Http.Controllers; using System.Web.Http.Dispatcher; namespace WebAPI.Custom{ public class CustomControllerSelector : DefaultHttpControllerSelector{ private HttpConfiguration _config; public CustomControllerSelector(HttpConfiguration config) : base(config){ _config = config; } public override HttpControllerDescriptor SelectController(HttpRequestMessage request){ var controllers = GetControllerMapping(); var routeData = request.GetRouteData(); var controllerName = routeData.Values["controller"].ToString(); string versionNumber = ""; string regex = @"application\/vnd\.demo\.([a-z]+)\.v(?<version>[0-9]+)\+([a-z]+)"; var acceptHeader = request.Headers.Accept .Where(a => Regex.IsMatch(a.MediaType, regex, RegexOptions.IgnoreCase)); if (acceptHeader.Any()){ var match = Regex.Match(acceptHeader.First().MediaType, regex, RegexOptions.IgnoreCase); versionNumber = match.Groups["version"].Value; } HttpControllerDescriptor controllerDescriptor; if (versionNumber == "1"){ controllerName = string.Concat(controllerName, "V1"); } else if (versionNumber == "2"){ controllerName = string.Concat(controllerName, "V2"); } if (controllers.TryGetValue(controllerName, out controllerDescriptor)){ return controllerDescriptor; } return null; } } }
WebApi.Config.cs −
示例
public static class WebApiConfig{ public static void Register(HttpConfiguration config){ config.Services.Replace(typeof(IHttpControllerSelector), new CustomControllerSelector(config)); config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } }
StudentV1Controller −
示例
using DemoWebApplication.Models; using System.Collections.Generic; using System.Linq; using System.Web.Http; namespace DemoWebApplication.Controllers{ public class StudentV1Controller : ApiController{ List<StudentV1> students = new List<StudentV1>{ new StudentV1{ Id = 1, Name = "Mark" }, new StudentV1{ Id = 2, Name = "John" } }; public IEnumerable<StudentV1> Get(){ return students; } public StudentV1 Get(int id){ var studentForId = students.FirstOrDefault(x => x.Id == id); return studentForId; } } }
StudentV2Controller −
示例
using DemoWebApplication.Models; using System.Collections.Generic; using System.Linq; using System.Web.Http; namespace DemoWebApplication.Controllers{ public class StudentV2Controller : ApiController{ List<StudentV2> students = new List<StudentV2>{ new StudentV2{ Id = 1, FirstName = "Roger", LastName = "Federer" }, new StudentV2{ Id = 2, FirstName = "Tom", LastName = "Bruce" } }; public IEnumerable<StudentV2> Get(){ return students; } public StudentV2 Get(int id){ var studentForId = students.FirstOrDefault(x => x.Id == id); return studentForId; } } }
以下輸出顯示了使用自定義媒體型別處理 StudentV1 和 StudentV2 控制器時獲得的結果。
因此,如果我們現在希望使用自定義媒體型別獲得 XML 格式的相同輸出,請在 webapiconfig.cs 中新增以下自定義媒體型別
示例
public static void Register(HttpConfiguration config){ config.MapHttpAttributeRoutes(); config.Services.Replace(typeof(IHttpControllerSelector), new CustomControllerSelector(config)); config.Formatters.XmlFormatter.SupportedMediaTypes .Add(new MediaTypeHeaderValue("application/vnd.demo.student.v1+xml")); config.Formatters.XmlFormatter.SupportedMediaTypes .Add(new MediaTypeHeaderValue("application/vnd.demo.student.v2+xml")); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); }
在上例中,我們看到輸出為 XML 格式,如自定義媒體型別中所指定。
廣告