有没有办法将unflattenModelState 键和值从 Mvc 转换为对象?

问题描述

我想获取一个 System.Web.Mvc.ModelStateDictionary 并将其转换(unflatten)为一个可读对象,该对象可以在 Json 中安全地序列化以进行日志记录。

模型状态输入看起来像这样:

{
    "FirstName": "Somebody","LastName": "Awesome","Emails[0].EmailType": "Primary","Emails[0].EmailAddress": "asdf@tempuri.com","Emails[0].UpdatedBy": "tester","UpdatedBy": null
}

我想要的输出是这样的:

{
    "Emails": {
        "0": {
            "EmailAddress": "asdf@tempuri.com","EmailType": "Primary","UpdatedBy": "tester"
        }
    },"FirstName": "Somebody","UpdatedBy": null
}

是否有内置的方法可以使用 Mvc 甚至外部库来完成此操作?

解决方法

执行此操作的本土函数是:

        public Dictionary<string,object> Convert(ModelStateDictionary modelState)
        {
            var o = new Dictionary<string,object>();

            var sorted = modelState.OrderBy(_ => _.Key).ToList();

            foreach (var ms in sorted)
            {
                string key = ms.Key;
                // each key starts at the root node
                var node = o;
                int i = 0;
                int ic = 0;
                string token;

                // extract each token and build dictionaries
                for (; i < key.Length - 1; i++)
                {
                    var c = key[i];
                    switch (c)
                    {
                        case '.':
                        // don't bother with lists just use a dictionary,just easier!
                        case '[':
                        case ']':
                            if (i - ic > 0)
                            {
                                token = key.Substring(ic,i - ic);
                                if (!node.TryGetValue(token,out var cn) || !(cn is Dictionary<string,object> v))
                                {
                                    node[token] = v = new Dictionary<string,object>();
                                }
                                node = v;
                            }
                            ic = i + 1;
                            break;
                        default:
                            break;
                    }
                }
                i++;

                token = key.Substring(ic,i - ic);
                node[token] = ms.Value.Value?.AttemptedValue;
            }

            return o;
        }