2014-05-21 29 views
0

我正在ASP.NET中編寫一個應用程序,以便在Azure網站中運行,該網站獲取一些JSON並根據用戶輸入返回值。例如:安全且高效地評估簡單的字符串以查詢.NET POCO

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

在上面的例子中,實現「GetValueFromObject」的最佳方法是什麼?我可以想到幾種可能性,但我不確定它們全部:

  • 解析用戶輸入字符串 - 在'。'上分割。和'[n]',然後用它來評估查詢。
  • 使用一些腳本引擎來評估表達式。
  • 轉換爲XML和解析的XPath的

是否有.NET本身事情要做到這一點,還是不錯的庫來獲得這種功能?

+0

在我看來,這樣將需要大量棘手的反思和分析來完成的,而不是你'你想嘗試打滾自己。你有沒有考慮過使用[IronPython](http://ironpython.net/)或[CS-Script](http://www.csscript.net/)? – mason

+0

我對CS-Script不熟悉,但這些都有可能性。我想我擔心1)腳本引擎過於「沉重」,2)用戶可能會發送惡意輸入。我應該有資格:這是一個在Azure網站上運行的ASP.NET應用程序... – Daniel

+0

@Daniel如果你想讓它真的輕量級(只是成員訪問或索引訪問),你自己寫它並不難。 – Andrey

回答

0

我的要求與您列出的要求幾乎相同,最後我不得不編寫自己的宏分析實用程序,該實用程序只允許訪問屬性和索引器。然後我確定這只是通過了一個旨在用於此目的的「基礎對象」。 (我們把這種特殊類型的POCO放在一個「MacroModel」命名空間中,以表明它們將用於宏。)

不幸的是,代碼是專有的,所以我不能指出你的意思,但我可以提供一些關於如何編寫它的建議。

  1. 使用兩個階段:一個解析器,通過查看字符串以找出正在發生哪些類型的操作,然後是一個評估程序,它使用解析結果爲給定對象生成結果。
  2. 爲解析器使用狀態機架構。不要試圖在一個大功能中進行解析。
  3. 單元測試它的廢話。這正是正是測試驅動開發真正發光的情況。
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]")); 

     } 
    } 
}