安全有效地评估简单字符串以查询.NET POCO

时间:2014-05-21 14:45:57

标签: c# .net parsing

我正在ASP.NET中编写一个应用程序,在Azure网站中运行,获取一些JSON并根据用户输入返回一个值。例如:

dynamic json = GetSomeJSONAndParseToDynamicClass();
var userInput = "somefield.somearray[20].somefield";
var output = GetValueFromObject(json,userInput);

在上面的例子中,实现“GetValueFromObject”的最佳方法是什么?我可以想到几种可能性,但我不确定所有这些可能性:

  • 解析用户输入字符串 - 拆分为“。”和'[n]',然后用它来评估查询。
  • 使用一些脚本引擎来评估表达式。
  • 转换为XML并解析为XPath

.NET本身有什么可以做到这一点,或者是一个很好的库来获得这种功能吗?

2 个答案:

答案 0 :(得分:0)

我有与你列出的内容几乎相同的要求,我最终不得不编写自己的宏解析实用程序,只允许访问属性和索引器。然后我确保只传递了一个用于此目的的“基础对象”。 (我们将这个特殊类别的POCO放在一个“MacroModel”命名空间中,表示它们将用于宏。)

不幸的是,代码是专有的,所以我不能指出它,但我可以就如何编写它提供一些建议。

  1. 使用两个阶段:通过字符串查找字符串以找出正在发生的操作类型的解析器,然后是使用解析结果生成给定对象的结果的求值程序。
  2. 为解析器使用状态机架构。不要试图在一个大函数中进行解析。
  3. 单位测试垃圾。这是完全那种测试驱动开发真正发挥作用的情况。

答案 1 :(得分:0)

如果你不需要太多,这对你有用:

using System;
using System.Linq;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace t1
{
    class SomeClass
    {
        public string Prop {
            get;
            set;
        }

        public List<int> list = new List<int>() {1,2,3};
    }

    class SomeAnotherClass
    {
        public SomeClass Obj {
            get;
            set;
        }
    }

    class MainClass
    {
        public static object GetDynamic(object o, string query) {
            var elems = query.Split ('.');
            var current = o;
            var indexer = new Regex (@"(\w+)\[(\d+)\]", RegexOptions.Compiled);
            foreach (var elem in elems)
            {
                var type = current.GetType ();
                var m = indexer.Match (elem);
                var memberName = elem;
                int? index = null;
                if (m.Success) {
                    memberName = m.Groups[1].Value;
                    index = int.Parse(m.Groups [2].Value);
                }

                var field = type.GetField (memberName);
                var prop = type.GetProperty (memberName);
                if (field != null)
                    current = field.GetValue (current);
                else if (prop != null)
                    current = prop.GetValue (current, null);
                else
                    throw new Exception ();

                if (index.HasValue)
                {
                    current = ((dynamic)current) [index.Value];
                }
            }
            return current;
        }

        public static void Main (string[] args)
        {
            object o = new SomeAnotherClass ()
            {
                Obj = new SomeClass()
                {
                    Prop = "asd"
                }
            };
            Console.WriteLine (GetDynamic(o, "Obj.list[1]"));

        }
    }
}