前一篇「在ASP.NET WEB AP 2進行APICONTROLLER層級的組態」是透過屬性(Attribute)設置方式來為ApiControler加入靜態設置。它無法在執行期間改變。
實作IControllerConfiguration介面
方法前一篇已經介紹過了:
public class JsonOnlyAttribute : Attribute, IControllerConfiguration { public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor) { controllerSettings.Formatters.Clear(); controllerSettings.Formatters.Add(new JsonMediaTypeFormatter()); } }
以上是僅提供JSON Formatter的範例,這樣的好處是不用整個ASP.NET Web API 2專案都完全關閉XML Formatter,需要關閉時才關閉。
如果你是希望動態進行Controller層級組態的話,其實前一篇的參考文件有留下一篇MVP Filip的參考文章,以下簡述Filip文章以瞭解如何進行動態Controller組態。
態動Controller層級組態
一、新增一個延伸方法:
public static class HttpConfigurationExtensions { /// <summary> /// 建立新HttpControllerSettings實體,並套用提供組態使用者的變更。 /// </summary> /// <param name="configuration">HttpConfiguration</param> /// <param name="settings">HttpControllerSettings</param> public static HttpConfiguration Copy(this HttpConfiguration configuration, Action<HttpControllerSettings> settings) { var controllerSettings = new HttpControllerSettings(configuration); settings(controllerSettings); // 呼叫HttpConfiguration私有建構子(NonPublic)以建立調整用的HttpControllerSettings組態物件 var constructor = typeof(HttpConfiguration).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(HttpConfiguration), typeof(HttpControllerSettings) }, null); var instance = (HttpConfiguration)constructor.Invoke(new object[] { configuration, controllerSettings }); return instance; } }
二、儲存組態設置
/// <summary> /// 儲存Controller組態 /// </summary> public class ControllerConfig { public static Dictionary<Type, Action<HttpControllerSettings>> Map = new Dictionary<Type, Action<HttpControllerSettings>>(); }
三、由自訂IHttpControllerActivator呼叫HttpConfigurationExtensions方法
public class PerControllerConfigActivator : IHttpControllerActivator { private static readonly DefaultHttpControllerActivator Default = new DefaultHttpControllerActivator(); private readonly ConcurrentDictionary"Type, HttpConfiguration> _cache = new ConcurrentDictionary<Type, HttpConfiguration>(); /// <summary> /// 建立 System.Web.Http.Controllers.IHttpController 物件。 /// </summary> /// <param name="request">訊息要求。</param> /// <param name="controllerDescriptor">HTTP 控制器描述元。</param> /// <param name="controllerType">控制器的型別。</param> /// <returns>IHttpController 物件</returns> public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType) { HttpConfiguration controllerConfig; // 檢查每一個當下的Controller,是否有我們要組態的Controller型別 // TryGetValue方法:嘗試從 ConcurrentDictionary<TKey, TValue> 取得與指定之索引鍵相關聯的值。 if (_cache.TryGetValue(controllerType, out controllerConfig)) { controllerDescriptor.Configuration = controllerConfig; } else if (ControllerConfig.Map.ContainsKey(controllerType)) { // 呼叫 HttpConfigurationExtensions.Copy方法 controllerDescriptor.Configuration = controllerDescriptor.Configuration.Copy(ControllerConfig.Map[controllerType]); // 為此Controller型別加入組態 // TryAdd方法:如果它不存在於字典中,加入新的索引鍵加入字典 _cache.TryAdd(controllerType, controllerDescriptor.Configuration); } // 建立新的IHttpcontroller var result = Default.Create(request, controllerDescriptor, controllerType); return result; } }
四、WebApiConfig進行動態組態
// 自訂IHttpControllerActivator,叫呼新HttpConfigurationExtensions方法, config.Services.Replace(typeof(IHttpControllerActivator), new PerControllerConfigActivator()); // 動態加入Controller層級設置 ControllerConfig.Map.Add(typeof(TodoItems2Controller), settings => { settings.Formatters.Clear(); var jsonformatter = new JsonMediaTypeFormatter { SerializerSettings = { ContractResolver = new CamelCasePropertyNamesContractResolver() } }; settings.Formatters.Add(jsonformatter); }); ControllerConfig.Map.Add(typeof(TodoItemsController), settings => { settings.Formatters.Clear(); settings.Formatters.Add(new XmlMediaTypeFormatter()); });
註解我都寫在程式碼之中了。注意,態動進行Controller層級組態與實作IControllerConfiguration介面的屬性設置方式無法併存,原因也很簡單,因為我們替換了自行實作的IHttpControllerActivator,它並不懂的如何解讀實作IControllerConfiguration介面的屬性。
沒有留言:
張貼留言
感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。