2013-02-01 196 views
2

我試圖接受的形式轉換查詢字符串數組參數到字典值

?param[key1]=value1&param[key2]=value2 

或可替代

?where[column1]=value1&where[column2]=value1 
&orderby[column1]=asc&orderby[column2]=desc 

的查詢字符串,並將其轉換成一個字典在C#中的MVC 4網API,因此可以作爲param["key1"]進行訪問。這在PHP中是微不足道的,但我一直無法找到任何在C#中重現這一點的方法。

我知道我可以通過

?param=value1&param=value2 

採取陣列,這樣我可以做類似

?where=column1&where=column2 
&whereval=value1&whereval=value2 
&orderby=column1&orderby=column2 
&orderbycard=asc&orderbycard=desc 

但還有排序的問題,是幾乎沒有,我的目的是有用的。

希望這不是框架的限制,我該如何在C#中實現字典式轉換,最好能夠在函數參數中使用字典?

澄清:我不想將查詢字符串轉換爲NVC,而是將查詢字符串參數轉換爲自己的NVC。這是不是就像ParseQueryString()或Request.QueryString對象一樣簡單。

This question被關閉的是的this question重複爲由最後一次,所以我增加了澄清。我會問,任何考慮將此標記爲重複的人都應考慮我在此之前要求的內容,以及認真看待我的示例。

+0

你能在一個url中顯示這個例子,這樣你就可以發佈一個替代解決方案..? – MethodMan

+0

類似於http://example.com/api/objects?where [id] = 4&orderby [id] = asc'的網址? –

+0

您可以擴展您期望如何訪問最終結果中的參數嗎?一個關鍵是「在哪裏(專欄)」還是僅僅是「專欄」?另外,無論哪種情況,預期值是多少? –

回答

3

有在的方式來實現這一結果沒有內置。下面是我的嘗試,使用具有命名組的正則表達式。可以跳過拆分並處理正則表達式本身中的?&字符,但我採用這種方法來保持模式更清晰。

​​

當然,這依賴於你知道的鑰匙,檢查前的手,如dict["where"]["column"]

您可能會發現ContainsKeyTryGetValue方法有助於檢查一個鍵的存在:

string result; 
if (dict["where"].TryGetValue("column", out result)) 
{ 
    Console.WriteLine(result); 
} 
+0

+1爲正則表達式組 –

+0

我希望修改Web API如何處理傳入的查詢字符串,但這是一個很好的選擇! –

0

你可以嘗試這樣的事情

var queryString = "http://example.com/api/objects?where[id]=4&orderby[id]=asc?"; 
string[] arr = queryString.Split(new char[] { '&' }); 
int cntVar = 0; // start key 
Dictionary<int, string> dictQuery; 
dictQuery = arr.ToDictionary(d => ++cntVar); 
0

我想根據Ahmad Mageed的工作向大家分享我的想法。 (這是一個很好的開始。)我需要相同的功能,但我需要它能夠在索引鏈中接受更多的深度。

這使您能夠根據需要讀取儘可能多的子索引,而無需對其進行硬編碼,以在2或3級深度停止。因此,通過此更新,您可以閱讀這樣的查詢字符串......

columns[0][data]=0&columns[0][name]=&columns[0][searchable]=true 
&columns[0][orderable]=true&columns[0][search][value]= 
&columns[0][search][regex]=false&columns[1][data]=1 
&columns[1][name]=&columns[1][searchable]=true 
&columns[1][orderable]=true&columns[1][search][value]= 
&columns[1][search][regex]=false&columns[2][data]=2 
... 
&order[0][column]=0&order[0][dir]=asc&start=0&length=10&search[value]=&search[regex]=false 

這是我更新後的那部分代碼版本。

public IDictionary ConvertQueryString(string sQry) 
{ 
    string pattern = @"(?<Prop>[^[]+)(?:\[(?<Key>[^]]+)\])*=(?<Value>.*)"; 
    // The brackets seem to be encoded as %5B and %5D 
    var qry = HttpUtility.UrlDecode(sQry); 

    var re = new Regex(pattern); 
    var dict = qry.Split(new[] { "?", "&" }, StringSplitOptions.RemoveEmptyEntries) 
       .Select(s => re.Match(s)).Where(g => g.Success) 
       .GroupBy(m => m.Groups["Prop"].Value) 
       .ToDictionary<IGrouping<string, Match>, string, object>(
        g => g.Key, 
        g => GetKey(g, 0)); 
    return dict; 
} 

private object GetKey(IGrouping<string, Match> grouping, int level) 
{ 
    var count = grouping.FirstOrDefault().Groups["Key"].Captures.Count; 
    // If the level is equal to the captures, then we are at the end of the indexes 
    if (count == level) 
    { 
     var gValue = grouping.Where(gr => gr.Success).FirstOrDefault(); 
     var value = gValue.Groups["Value"].Value; 
     return value; 
    } 
    else 
    { 
     return grouping.Where(gr => gr.Success) 
       .GroupBy(m => m.Groups["Key"].Captures[level].Value) 
       .ToDictionary<IGrouping<string, Match>, string, object>(
         a => a.Key, 
         a => GetKey(a, level + 1)); 
    } 
} 

我想進一步建立一個嵌套的字典對象,我想實際上建立基於傳遞的字符串的對象。我需要這個用於新版本的jQuery DataTables,它實際上是產生上面那個令人討厭的查詢字符串的東西。這是一個快速寫,所以它有點粗糙,可能有點容易出錯,因爲我還沒有時間來鞏固它。

// Call it like so. 
MyClass object = new MyClass(); 
WalkDictionary(dict, object); 
// At this point the object will be filled out for you. 

public class MyClass 
{ 
    public List<cColumns> columns { get; set; } 
    public cSearch search { get; set; } 
} 
public class cColumns 
{ 
    public int? data { get; set; } 
    public string name { get; set; } 
    public bool? searchable { get; set; } 
    public bool? orderable { get; set; } 
    public cSearch search { get; set; } 
} 
public class cSearch 
{ 
    public string value { get; set; } 
    public bool? regex { get; set; } 
} 

我只把我需要的基本類型。所以,如果你需要/想要更多,那麼你將不得不添加它們。

private void WalkDictionary(IDictionary dict, object obj) 
{ 
    foreach (string key in dict.Keys) 
    { 
     Type t = obj.GetType(); 
     if (t.IsGenericType 
      && typeof(List<>) == t.GetGenericTypeDefinition()) 
     { 
      Type[] typeParameters = t.GetGenericArguments(); 
      foreach (DictionaryEntry item in dict) 
      { 
       var lstPropObj = Activator.CreateInstance(typeParameters[0]); 
       WalkDictionary((IDictionary)item.Value, lstPropObj); 
       ((IList)obj).Add(lstPropObj); 
      } 
      return; 
     } 
     PropertyInfo prop = obj.GetType().GetProperty(key); 
     if (prop == null) 
      continue; 
     if (dict[key] is IDictionary) 
     { 
      //Walk 
      var objProp = prop.GetValue(obj); 
      if (objProp == null) 
       objProp = Activator.CreateInstance(prop.PropertyType); 
      WalkDictionary(dict[key] as IDictionary, objProp); 
      prop.SetValue(obj, objProp); 
     } 
     else if (prop.PropertyType.IsAssignableFrom(typeof(int))) 
     { 
      int val = Convert.ToInt32(dict[key]); 
      prop.SetValue(obj, val); 
     } 
     else if (prop.PropertyType.IsAssignableFrom(typeof(bool))) 
     { 
      bool val = Convert.ToBoolean(dict[key]); 
      prop.SetValue(obj, val); 
     } 
     else if (prop.PropertyType.IsAssignableFrom(typeof(string))) 
     { 
      string val = Convert.ToString(dict[key]); 
      prop.SetValue(obj, val); 
     } 
    } 
}