前一篇「在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介面的屬性。
沒有留言:
張貼留言
感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。