首先,你必须与微软的“ActionFilterAttribute”理念脱节。这将所有逻辑放在一个地方,但它令人困惑,因为属性和过滤器是两个完全不同的东西。
在这种情况下,您需要将它们分开,以便过滤器可以检测多个属性并对数据执行您想要的操作(这有点不清楚,但我想您会将某种列表放入 ViewData)。
资源属性
首先,我们有属性定义。它需要用 AttributeUsage 属性特别标记,以便可以多次使用,因此可以在控制器和操作方法上使用(我假设您希望聚合当前控制器和操作上的所有属性,但是你不必那样做)。
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = true)]
public class ResourceAttribute : Attribute
{
public ResourceAttribute(string name, string value)
{
this.Name = name;
this.Value = value;
}
public string Name { get; private set; }
public string Value { get; private set; }
}
资源过滤器
然后只需使用反射来获取属性实例,就像在任何地方获取属性实例一样。有一种方便的ActionDescriptor
方法可以让您直接访问动作和控制器类型。
上下文还使您可以直接访问ViewData
.
public class ResourceFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext filterContext)
{
var attributes = this.GetAllAttributes(filterContext.ActionDescriptor);
foreach (ResourceAttribute attribute in attributes)
{
var name = attribute.Name;
var value = attribute.Value;
// Do something with the meta-data from the attribute...
}
if (attributes.Any())
{
// Set the ViewData only when there are attributes
filterContext.Controller.ViewData["SomeKey"] = "SomeValue";
}
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
// Do nothing
}
public IEnumerable<ResourceAttribute> GetAllAttributes(ActionDescriptor actionDescriptor)
{
var result = new List<ResourceAttribute>();
// Check if the attribute exists on the action method
result.AddRange(
actionDescriptor
.GetCustomAttributes(typeof(ResourceAttribute), false) as ResourceAttribute[]
);
// Check if the attribute exists on the controller
result.AddRange(
actionDescriptor
.ControllerDescriptor
.GetCustomAttributes(typeof(ResourceAttribute), false) as ResourceAttribute[]
);
return result;
}
}
用法
现在,您只需将这些部件放置到位。首先,注册动作过滤器。
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
// Register the filter globally
filters.Add(new ResourceFilter());
filters.Add(new HandleErrorAttribute());
}
}
然后相应地装饰您的控制器和操作。过滤器每次都会运行,因此您需要确保其中有一个条件,使其仅在有要处理的属性时才输出 ViewData。