ActionAttribute
在WebAPI中,通常都繪有需要客製化ActionFilter的情況發生
執行順序不固定
ActionFilter的執行順序並非在上面的就優先執行,Filter有個FilterScope來表示他屬於何種層級的ActionFilter,執行順序依次是 Global , Controller , Action 。但如果是在同一層級的ActionFilter順序則未必按照固定。
]
測試
裡面全部都一樣繼承ActionFilterAttribute即可
1
| public class FourAttribute :ActionFilterAttribute{ }
|
註冊OneAttribute到Global
將其它Attribute分別註冊到Controller與Action
在Get中補上以下程式然後執行看看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| [HttpGet] [Three] [Four] public IEnumerable<Tuple<string,string>> Get() { IHttpActionSelector actionSelector = this.Configuration.Services.GetActionSelector(); HttpActionDescriptor actionDescriptor = actionSelector.SelectAction(this.ControllerContext); foreach (FilterInfo filterInfo in actionDescriptor.GetFilterPipeline()) { yield return new Tuple<string, string>( filterInfo.Instance.GetType().Name, filterInfo.Scope.ToString() ); } }
|
測試結果
排序依據所對應的層級,雖然這邊排序與我們在程式上的排序相同。但實際上順序同層級的順序未必是由上而下,為了避免這樣的問題,最好的方法就是在ActionFilter加上排序的屬性來解決。
實作Order屬性
定義IOrderAttribute
1 2 3 4 5 6 7 8 9
| public interface IOrderAttribute { int Order { get; set; } }
public class FourAttribute : ActionFilterAttribute, IOrderAttribute { public int Order { get; set; } }
|
實做IComparable介面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public class CustomFilterInfo : IComparable { public IFilter Instance { get; set; } public FilterScope Scope { get; set; } public CustomFilterInfo(IFilter instance, FilterScope scope) { this.Instance = instance; this.Scope = scope; } public int CompareTo(object obj) { if (obj is CustomFilterInfo) { var item = obj as CustomFilterInfo; if (item.Instance is IAttribute) { var attr = item.Instance as IAttribute; return (this.Instance as IAttribute).Order.CompareTo(attr.Order); } } return 0; } public FilterInfo ConvertToFilterInfo() { return new FilterInfo(this.Instance, this.Scope); } }
|
實做IFilterProvider介面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class CustomFilterProvider : IFilterProvider { public IEnumerable<FilterInfo> GetFilters( HttpConfiguration configuration, HttpActionDescriptor actionDescriptor) { IEnumerable<CustomFilterInfo> customActionFilters = actionDescriptor.GetFilters() .Select(i => new CustomFilterInfo(i, FilterScope.Controller)); IEnumerable<CustomFilterInfo> customControllerFilters = actionDescriptor.ControllerDescriptor .GetFilters() .Select(i => new CustomFilterInfo(i, FilterScope.Controller)); return customControllerFilters.Concat(customActionFilters) .OrderBy(i => i) .Select(i => i.ConvertToFilterInfo()); } }
|
Global註冊
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| protected void Application_Start() { AreaRegistration.RegisterAllAreas(); GlobalConfiguration.Configure(WebApiConfig.Register); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear(); GlobalConfiguration.Configuration.Filters.Add(new OneAttribute()); GlobalConfiguration.Configuration.Services.Add( typeof(System.Web.Http.Filters.IFilterProvider), new CustomFilterProvider()); var providers = GlobalConfiguration.Configuration.Services.GetFilterProviders(); var defaultprovider = providers.First(i => i is ActionDescriptorFilterProvider); GlobalConfiguration.Configuration.Services.Remove( typeof(System.Web.Http.Filters.IFilterProvider), defaultprovider); }
|
測試
將Attibute補上Order再執行看看得到的順序
可以看到Four排在Three的前面了