C# 将查询字符串数组参数转换为字典值

C# 将查询字符串数组参数转换为字典值,c#,asp.net-web-api,C#,Asp.net Web Api,我正在尝试接受表单的查询字符串 ?param[key1]=value1&param[key2]=value2 或者 ?where[column1]=value1&where[column2]=value1 &orderby[column1]=asc&orderby[column2]=desc 并将其转换为C#MVC4 Web API中的字典,以便可以通过param[“key1”]访问它。这在PHP中很容易做到,但我还没有找到任何方法在C#中重现这一点 我知道我

我正在尝试接受表单的查询字符串

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

?where[column1]=value1&where[column2]=value1
&orderby[column1]=asc&orderby[column2]=desc
并将其转换为C#MVC4 Web 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对象那么简单


上一次被关闭是因为它是的复制品,所以我补充了澄清。我想让任何人把这个标记成一个复制品,在我这样做之前仔细考虑一下我的问题,同时认真地看一下我的例子。
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);
var queryString=”http://example.com/api/objects?where[id]=4&orderby[id]=asc?”;
字符串[]arr=queryString.Split(新字符[]{'&});
int cntVar=0;//开始键
词典查询;
dictQuery=arr.ToDictionary(d=>++cntVar);

实现这一结果没有内在的方法。下面是我的尝试,使用带有命名组的正则表达式。可以跳过拆分并处理正则表达式本身中的
&
字符,但我采用这种方法来保持模式更干净

string input = "?where[column]=value&where[column2]=value2&orderby[column]=asc&orderby[column2]=desc";
string pattern = @"(?<Type>[^[]+)\[(?<Key>[^]]+)\]=(?<Value>.+)";
var re = new Regex(pattern);
var dict = input.Split(new[] { "?", "&" }, StringSplitOptions.RemoveEmptyEntries)
                .Select(s => re.Match(s))
                .GroupBy(m => m.Groups["Type"].Value)
                .ToDictionary(g => g.Key,
                    g => g.ToDictionary(x => x.Groups["Key"].Value,
                                        x => x.Groups["Value"].Value));

foreach (var t in dict.Keys)
{
    Console.WriteLine("Type: " + t);
    foreach (var k in dict[t].Keys)
    {
        Console.WriteLine("{0}: {1}", k, dict[t][k]);
    }
}

我想和你们分享我根据艾哈迈德·马吉德的作品提出的想法。(顺便说一句,这是一个很好的开始。)我需要同样的功能,但我需要它能够接受索引链中更多的深度

这使您能够根据需要读取任意多的子索引,而无需硬编码,使其停止在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));
    }
}
公共IDictionary ConvertQueryString(字符串sQry)
{
字符串模式=@“(?[^[]+)(?:\[(?[^]]+)\])*=(?*”;
//括号似乎编码为%5B和%5D
var qry=HttpUtility.UrlDecode(sQry);
var re=新正则表达式(模式);
var dict=qry.Split(新[]{“?”,“&”},StringSplitOptions.RemoveEmptyEntries)
.Select(s=>re.Match(s))。其中(g=>g.Success)
.GroupBy(m=>m.Groups[“Prop”].Value)
.ToDictionary(
g=>g.键,
g=>GetKey(g,0));
返回命令;
}
私有对象GetKey(iGroup分组,int级别)
{
var count=grouping.FirstOrDefault().Groups[“Key”].Captures.count;
//如果级别等于捕获,那么我们就在索引的末尾
如果(计数=级别)
{
var gValue=grouping.Where(gr=>gr.Success).FirstOrDefault();
var值=gValue.组[“值”].值;
返回值;
}
其他的
{
返回分组。其中(gr=>gr.Success)
.GroupBy(m=>m.Groups[“Key”]”。捕获[level]。值)
.ToDictionary(
a=>a.键,
a=>GetKey(a,级别+1));
}
}
我想做的不仅仅是构建一个嵌套的dictionary对象,而是基于传递的字符串实际构建对象。我在jQueryDataTables的新版本中需要它,它实际上是产生上面看起来很糟糕的查询字符串的原因。这是一个快速的写作,所以它有点粗糙,可能有点容易出错,因为我还没有时间来强化它

// 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; }
}
//就这样说吧。
MyClass对象=新的MyClass();
WalkDictionary(dict,object);
//此时将为您填写对象。
公共类MyClass
{
公共列表列{get;set;}
公共cSearch搜索{get;set;}
}
公共类cColumns
{
公共int?数据{get;set;}
公共字符串名称{get;set;}
公共布尔?可搜索{get;set;}
公共布尔?可排序{get;set;}
公共cSearch搜索{get;set;}
}
公共类研究
{
公共字符串值{get;set;}
公共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);
        }
    }
}
专用字典(IDictionary dict,object obj)
{
foreach(dict.Keys中的字符串键)
{
类型t=obj.GetType();
if(t.IsGenericType
&&typeof(List)==t.GetGenericTypeDefinition()
{
Type[]typeParameters=t.GetGenericArguments();
foreach(DictionaryEntry条目在dict中)
{
var lstPropObj=Activator.CreateInstance(类型参数[0]);
WalkDictionary((IDictionary)item.Value,lstproObj);
((IList)对象)添加(lstPropObj);
}
返回;
}
PropertyInfo prop=obj.GetType().GetProperty(键);
if(prop==null)
继续;
if(dict[key]是IDictionary)
{
//走
var objProp=prop.GetValue(obj);
if(objProp==null)
objProp=Activator.CreateInstance(prop.PropertyType);
WalkDictionary(dict[key]作为IDictionary,objProp);
属性设置值(obj、objProp);
}
else if(prop.PropertyType.IsAssignableFrom(typeof(int)))
{
int val=Convert.ToInt32(dict[key]);
属性设置值(对象、值);
}
else if(prop.PropertyType.IsAssignableFrom(typeof(bool)))
{
bool val=Convert.ToBoolean(dict[key]);
属性设置值(对象、值);
}
else if(prop.PropertyType.IsAssignableFro
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);
        }
    }
}