【问题标题】:C# Action Filter to serialize several resx files to JSONC# Action Filter 将多个 resx 文件序列化为 JSON
【发布时间】:2016-06-17 18:55:10
【问题描述】:

总的来说,我是操作过滤器的新手,一直想知道它是如何工作的。这看起来是一个很好的学习机会……

我们正在替换 Castle Monorail 应用程序的 UI,我想保留或实现类似于 [Resource] 属性的功能,它作为自定义操作过滤器提供,将字符串写入视图包,以便我们可以将它们写入全局范围内的 JSON 对象并在 JavaScript 中使用它们。

目前,我们像这样装饰控制器类(当然我会装饰控制器方法):

[Resource("common", "namespace.Resources.Common")]
[Resource("events", "namespace.Resources.Events")]
[Resource("people", "namespace.Resources.People")]
public class someController : BaseController

我的问题是: “我如何编写一个动作过滤器来构建来自个人使用的资源列表并将它们存放到模型或视图袋变量中?” ……或者可能…… “我如何编写一个可以多次调用的操作过滤器,而不会覆盖以前调用的数据?”

我已经阅读了我能找到的教程和文章,但是我发现的任何关于在单个控制器方法上多次调用动作过滤器的信息几乎肯定是关于控制执行顺序,而不是它的实际实现方式。

我欢迎任何代码/伪代码为我揭开这个神秘面纱。

提前致谢

【问题讨论】:

    标签: c# action-filter actionfilterattribute custom-action-filter


    【解决方案1】:

    首先,你必须与微软的“ActionFilterAttribute”理念脱节。这将所有逻辑放在一个位置,但令人困惑,因为 Attributes 和 Filters 是两个完全不同的东西。

    在这种情况下,您需要将它们分开,以便过滤器可以检测多个属性并对数据执行您想要的操作(这有点不清楚,但我想您会将某种列表放入 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。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-16
      • 2020-11-01
      • 1970-01-01
      • 2021-12-18
      • 1970-01-01
      相关资源
      最近更新 更多