在ASP.NET Web API進行Controller層級的組態
在ASP.NET Web API要進行組態設置的話,一般會到WebApiConfig.cs進行設置。不過有個好玩的問題,在WebApiConfig.cs進行的組態都是以HttpConfiguration物件在進行操作,MSDN說明表示 HttpServer 執行個體的設定。
。也就是說,不管你在何處進行設置,設置之後,它影響是的整個ASP.NET Web API(即HttpServer執行範圍)。
Model:TodoItem
以下是範例Model:
public class TodoItem { public int Id { get; set; } public string Name { get; set; } public bool IsDone { get; set; } }
然後利用基架含Entity Framework產生TodoItemsConteoller。建置之後,先利用POSTMAN等工具,新增幾筆資料:
小寫開頭(CamelCase)
JSON.NET預設序列化依照TodoItem的屬性名稱來輸出,現在有個簡單的需求,希望可以改採小寫開頭(CamelCase)的方式,那麼可以在WebApiConfig.cs這樣設置:
public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); // 省略 } }
設置CamelCasePropertyNamesContractResolver之後,解決第一個需求:小寫開頭。
HttpConfiguration的全面性
全域設置影響範圍太大,現在需求改變,希望所需的ApiController類別進行設定即可,那麼我們把腦筋動到ApiController裡面:
public class TodoItemsController : ApiController { private TodoContext db = new TodoContext(); private TodoItemsController() { // 無法在建構函式修改Configuration設置 //Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); } // GET: api/TodoItems public IQueryableGetTodoItems() { Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); return db.TodoItems; } // 省略 }
當我們要求過"/api/TodoItems"(執行過Configuration設置之後)再存取其他ApiController,你能發現,其他ApiController也會受影響。就算利用ActionFilter也是一樣,只要執行過HttpConfiguration的設置,影響都會是全面性的。
IControllerConfiguration介面
要在ASP.NET Web API進行Controller層級組態,那麼要使用IControllerConfiguration介面來進行Controller層級的設置,然後套用至所需的ApiController類別。
public interface IControllerConfiguration { void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor); }
介面定義一個Initialize方法,叫用回呼(Callback)以設定此 controllerDescriptor 的各控制器覆寫。其中的HttpControllerSettings是要初始化的控制器設定。
public sealed class HttpControllerSettings { public MediaTypeFormatterCollection Formatters { get; } public ParameterBindingRulesCollection ParameterBindingRules { get; } public ServicesContainer Services { get; } }
- Formatters:取得控制器的 MediaTypeFormatter 執行個體集合。
- ParameterBindingRules:取得控制器的參數繫結函數集合。
- Services:取得控制器的服務執行個體集合。
實作CamelCasedJsonAttribute
public class CamelCaseJsonAttribute : Attribute, IControllerConfiguration { public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor) { var jsonformatter = controllerSettings.Formatters.JsonFormatter; // 為Controller移除JsonFormatter controllerSettings.Formatters.Remove(jsonformatter); // 含CamelCasePropertyNamesContractResolver設置的Jsonformatter jsonformatter = new JsonMediaTypeFormatter { SerializerSettings = { ContractResolver = new CamelCasePropertyNamesContractResolver() } }; // 為Controller設置新增formatter controllerSettings.Formatters.Insert(0, jsonformatter); } }
注意一下,最後一行,請不要使用 add 來加入,因為以上是使用移除再加入的方式,使用add會改變formatter的順序,設置此屬性的ApiContrller會以XML Formatter為主,JSON Formatter為副。有設置Content-Type是不會有問題,但忘了設置或設置錯誤,程式會直接爆炸了!
這裡對Formatter進行Controller層級的設置,然後設置到我們所需的ApiController:
[CamelCaseJson] public class TodoItemsController : ApiController {}
執行"api/TodoItems"可以產生符合需求的小寫開頭名稱來輸出。另執行"api/TodoItems2"(Model - TodoItem產生另一個ApiController)則會採用預設名稱輸出。
如果你的Web API已經不提供XMLFormatter的話,也可以這樣寫:
// 清除所有Formatters controllerSettings.Formatters.Clear(); // 含CamelCasePropertyNamesContractResolver設置的Jsonformatter var jsonformatter = controllerSettings.Formatters.JsonFormatter; jsonformatter = new JsonMediaTypeFormatter { SerializerSettings = { ContractResolver = new CamelCasePropertyNamesContractResolver() } }; // 只加入json formatter controllerSettings.Formatters.Add(jsonformatter);
這樣可以確保不管是誰來要求,都會回應JSON內容。
以上需求來自Sky Chang的真實專案需求 :D
沒有留言:
張貼留言
感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。