从反射方法

时间:2016-07-12 12:29:02

标签: c# json rest model-view-controller

我从 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;

我现在需要帮助的是关于如何动态处理各种结果的任何建议。这意味着我需要一些帮助 理解 如何创建一个类来处理数据表中行的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
                    });
                }
            }

基本上这只处理工作场所(DataComponent中的特定DataSet)。

我目前的解决方案:

 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;
        }

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

1 个答案:

答案 0 :(得分:2)

我同意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,因为它不是一个非常独立于平台的解决方案 - 如果请求的应用程序是非.NET语言,它将更容易解析与DataTable相比较的Json数组。如果你必须使用DataTable,你可以查看.Net的DataTable.ToXML()扩展方法,但是我遇到了一些问题,特殊字符没有很好地转换为XML以及其他一些问题。

如果您想使用推荐的json路径,您请求的数据必须足以查询数据库(即:RequestType =“jobSiteReport”,MinDate =“7/1/2016”,MaxDate =“7 /二千零十六分之十二“ )。根据“RequestType”的含义,使用它来查询数据库或生成数据(如果您满意,则生成DataSet或DataTable)。使用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数据的字符串,其中包含DataTable的所有结果。然后你就可以归还了。 (您也可以使用SqlDataReader来完成相同的结果,而不使用DataTable作为中间步骤 - 从SqlDataReader填充列表,将列表转换为数组,然后将数组序列化为json。)

如果您正在创建架构,则应创建有关请求者应该接收的内容的文档。

Json.Net还有从json反序列化强类型对象,反序列化匿名类型等的方法。你应该阅读可用的东西 - 我确信它有一些非常适合你想要的东西实现