在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 IQueryable GetTodoItems()
{
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


沒有留言:
張貼留言
感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。