从反射的方法动态创建 JSON 对象

本文关键字:JSON 对象 创建 动态 反射的 方法 | 更新日期: 2023-09-27 17:56:38

自从我从SO Hivemind那里得到了一堆帮助,我就能够创建一个REST API(C#,MVC),通过捕获字符串参数并通过使用反射找到正确的方法来处理动态(至少我想这样称呼它)调用。

 var myType = typeof(JaberoDC.JaberoDC.JaberoDC);

            var method = myType
                .GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
                .Single(mi =>mi.ReturnType == typeof(DataSet) 
                && string.Equals(mi.Name, param, StringComparison.OrdinalIgnoreCase));
            var subject = Activator.CreateInstance(myType);
            var result = method.Invoke(subject, new Object[] { "", conStr, "", 0, 0, null });

            DataSet ds = (DataSet)result;

我现在需要帮助的是有关如何动态处理各种结果的任何建议。这意味着我需要一些帮助来了解如何创建一个类来处理 DataTable 中行中的 0=>N 列(从 DS 获取 DT 后),或者如何在不创建上述类的实例的情况下序列化数据。

同样,如果我的术语在这里不对,我很抱歉。

我基本上被扔进了我现在的雇主的深渊,为一个有几百个方法的DataComponent创建一个REST API。就像现在一样,API 仅在使用以下代码时才有效:

List<Worksite> arr2 = new List<Worksite>();
            foreach (DataTable table in ds.Tables)
            {
                foreach (DataRow row in table.Rows)
                {
                    string id = row["JobID"].ToString();
                    string name = row["JobName"].ToString();
                    string site = row["SiteName"].ToString();
                    arr2.Add(new Worksite
                    {
                        ID = id,
                        JobName = name,
                        SiteName = site
                    });
                }
            }

基本上,这只处理工作站点(数据组件中的特定数据集)。

我目前的解决方案:

 public string GetFromParam(String param)
        {
            var myType = typeof(JaberoDC.JaberoDC.JaberoDC);

            var method = myType
                .GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
                .Single(mi =>mi.ReturnType == typeof(DataSet) 
                && string.Equals(mi.Name, param, StringComparison.OrdinalIgnoreCase));
            var subject = Activator.CreateInstance(myType);
            var result = method.Invoke(subject, new Object[] { "", conStr, "", 0, 0, null });

            DataSet ds = (DataSet)result;
            List<GenerateModel> arr2 = new List<GenerateModel>();
            int count = 0;
            List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
            Dictionary <string, object> dicRow;
            foreach (DataTable table in ds.Tables)
            {
                foreach (DataRow row in table.Rows)
                {
                    dicRow = new Dictionary<string, object>();
                    foreach (DataColumn col in table.Columns){
                        dicRow.Add(col.ColumnName, row[col]);
                    }
                    rows.Add(dicRow);
                }
            }
//            for (int i = 0; i < ds.Tables.)
            string json = JsonConvert.SerializeObject(rows);
            return json;
        }

我基本上在标记的答案中使用建议的解决方案,同时还使用字典来保存数据键值对问题的动态解决方案。

从反射的方法动态创建 JSON 对象

我同意Clint关于使用Newtonsoft Json.net 的评论。 这有很多辅助方法,可以让您的生活更轻松。

理想情况下,您将为期望接收的每种类型的数据创建一个控制器。 然后,可以使用传入数据创建类的实例,该实例是根据将要接收的内容建模的。 使用 RESTful API 和 MVC,我将传入数据视为 FormDataCollection,这就像必须按顺序处理的键值对的传入流。 下面是一个代码示例,可为您指明正确的方向:

// POST api/mycontrollername
public HttpResponseMessage Post(FormDataCollection fdc)
{
    try
    {
        if (fdc != null)
        {
            MyClass myInstance = new MyClass();
            IEnumerator<KeyValuePair<string, string>> pairs = fdc.GetEnumerator();
            while (pairs.MoveNext())
            {
                switch (pairs.Current.Key)
                {
                    case "PhoneNumber":
                        myInstance.PhoneNumber = pairs.Current.Value;
                        break;
                    ...
                    default:
                        // handle any additional columns
                        break;
                }
            }
            // do stuff with myInstance
            // respond with OK notification
        }
        else
        {
            // respond with bad request notification
        }
    }
    catch (Exception ex)
    {
        // respond with internal server error notification
    }
}

如果必须使用同一控制器处理多种数据类型,则可能有一个特定的数据字段可以为您提供有关接收内容的线索,以便您可以适当地处理它。 如果你真的不知道你在任何时候收到什么,你可以把它转换为动态类型并使用反射,但听起来数据发送者正在为你设置一个艰难的集成在这种情况下 - 这绝对不是我设计 API 的方式......

编辑:(根据您的评论澄清)您似乎希望使用单个控制器接受任意数量的数据类型的请求,并返回包含结果的 DataTable,即使您事先不知道 DataTable 将包含哪些字段。

首先,除非是特定要求,否则我不会使用 DataTable,因为它不是一个非常独立于平台的解决方案 - 如果请求应用程序使用的是 non-.NET 语言,则与 DataTable 相比,解析 Json 数组会更容易。 如果必须使用数据表,则可以查看 。Net的DataTable.ToXML()扩展方法,但我遇到了特殊字符不能很好地转换为XML的问题,以及这种方法的其他一些问题。

如果要使用推荐的 json 路由,则请求的数据必须足以查询数据库(即:RequestType = "jobSiteReport",MinDate = "7/1/2016",MaxDate = "7/12/2016")。 使用它来查询数据库或生成数据(如果您喜欢的话,则生成到数据集或数据表中),具体取决于"请求类型"是什么。 使用 Linq 或循环或其他方法将 DataTable 转换为对象数组(如果需要,这可能是匿名类型,但我更喜欢在可以选择时保持强类型。 这是伪代码,但应该让你明白我的意思:

//using Newtonsoft.Json;
List<MyObject> objects = new List<MyObject>();
for (int i = 0; i < dt.Rows.Count; i++)
{
    MyObject obj = new MyObject()
    obj.Time = dt.Rows[i]["Time"];
    obj.Person = dt.Rows[i]["PersonID"];
    ...
    objects.Add(obj);
}
string json = JsonConvert.SerializeObject(objects.ToArray());

现在,你有一个字符串,其中包含 json 数据以及数据表中的所有结果。然后你可以返回它。 (您也可以使用 SqlDataReader 来完成相同的结果,而无需使用 DataTable 作为中间步骤 - 从 SqlDataReader 填充列表,将列表转换为数组,然后将数组序列化为 json。

如果您正在发明架构,则应创建有关请求者应期望收到的内容的文档。

Json.Net 还具有从 JSON 反序列化强类型对象、反序列化匿名类型等的方法。 您应该阅读可用的内容 - 我相信它有一些非常适合您想要实现的目标的东西。